package com.zhiche.wms.service.log.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zhiche.wms.configuration.MyConfigurationProperties;
import com.zhiche.wms.core.supports.BaseException;
import com.zhiche.wms.core.supports.constant.OpConstant;
import com.zhiche.wms.core.supports.enums.InterfaceAddrEnum;
import com.zhiche.wms.core.supports.enums.SysSourceEnum;
import com.zhiche.wms.core.supports.enums.TableStatusEnum;
import com.zhiche.wms.core.supports.enums.UomEnum;
import com.zhiche.wms.core.utils.HttpRequestUtil;
import com.zhiche.wms.core.utils.SnowFlakeId;
import com.zhiche.wms.domain.mapper.log.ItfImplogHeaderMapper;
import com.zhiche.wms.domain.model.base.Storehouse;
import com.zhiche.wms.domain.model.inbound.InboundNoticeHeader;
import com.zhiche.wms.domain.model.inbound.InboundNoticeLine;
import com.zhiche.wms.domain.model.log.ItfImplogHeader;
import com.zhiche.wms.domain.model.log.ItfImplogLine;
import com.zhiche.wms.domain.model.opbaas.OpDeliveryPoint;
import com.zhiche.wms.domain.model.opbaas.OpTask;
import com.zhiche.wms.domain.model.otm.OtmOrderRelease;
import com.zhiche.wms.domain.model.otm.OtmShipment;
import com.zhiche.wms.domain.model.otm.ShipmentOTMResultDTO;
import com.zhiche.wms.domain.model.outbound.OutboundKeyPrepareLine;
import com.zhiche.wms.domain.model.outbound.OutboundNoticeHeader;
import com.zhiche.wms.domain.model.outbound.OutboundNoticeLine;
import com.zhiche.wms.domain.model.outbound.OutboundPrepareLine;
import com.zhiche.wms.dto.interfacedto.InboundNoticeFromTMSDTO;
import com.zhiche.wms.dto.interfacedto.OutboundNoticeFromTMSDTO;
import com.zhiche.wms.dto.interfacedto.UpdateInboundFromTMSDTO;
import com.zhiche.wms.service.base.IBusinessDocNumberService;
import com.zhiche.wms.service.base.IStorehouseService;
import com.zhiche.wms.service.constant.*;
import com.zhiche.wms.service.dto.ShipTaskDTO;
import com.zhiche.wms.service.dto.ShipmentDTO;
import com.zhiche.wms.service.inbound.IInboundNoticeHeaderService;
import com.zhiche.wms.service.inbound.IInboundNoticeLineService;
import com.zhiche.wms.service.log.IItfImplogHeaderService;
import com.zhiche.wms.service.log.IItfImplogLineService;
import com.zhiche.wms.service.opbaas.IDeliveryPointService;
import com.zhiche.wms.service.opbaas.ITaskService;
import com.zhiche.wms.service.otm.IOtmOrderReleaseService;
import com.zhiche.wms.service.otm.IOtmShipmentService;
import com.zhiche.wms.service.outbound.IOutboundKeyPrepareLineService;
import com.zhiche.wms.service.outbound.IOutboundNoticeHeaderService;
import com.zhiche.wms.service.outbound.IOutboundNoticeLineService;
import com.zhiche.wms.service.outbound.IOutboundPrepareLineService;
import com.zhiche.wms.service.utils.OtmShipmentParse;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 * 仓储接口导入日志头 服务实现类
 * </p>
 *
 * @author qichao
 * @since 2018-06-11
 */
@Service
public class ItfImplogHeaderServiceImpl extends ServiceImpl<ItfImplogHeaderMapper, ItfImplogHeader> implements IItfImplogHeaderService {

    public Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private MyConfigurationProperties properties;
    @Autowired
    private SnowFlakeId snowFlakeId;
    @Autowired
    private IStorehouseService storehouseService;
    @Autowired
    private IItfImplogLineService itfImplogLineService;
    @Autowired
    private IOtmShipmentService otmShipmentService;
    @Autowired
    private IOtmOrderReleaseService releaseService;
    @Autowired
    private IDeliveryPointService deliveryPointService;
    @Autowired
    private ITaskService taskService;
    @Autowired
    private IBusinessDocNumberService businessDocNumberService;
    @Autowired
    private IInboundNoticeHeaderService inboundNoticeHeaderService;
    @Autowired
    private IInboundNoticeLineService inboundNoticeLineService;
    @Autowired
    private IOutboundNoticeHeaderService outboundNoticeHeaderService;
    @Autowired
    private IOutboundNoticeLineService outboundNoticeLineService;
    @Autowired
    private IBusinessDocNumberService iBusinessDocNumberService;
    @Autowired
    private IOutboundPrepareLineService prepareLineService;
    @Autowired
    private IOutboundKeyPrepareLineService keyPrepareLineService;

    @Value("${wms.properties.outboundWarehouse}")
    private String outboundWarehouse;
    @Value("${wms.properties.inboundWarehouse}")
    private String inboundWarehouse;

    @Override
    public void otmShipmentImport(String shipment) throws Exception {
        ItfImplogHeader itfImplogHeader = new ItfImplogHeader();
        itfImplogHeader.setId(snowFlakeId.nextId());
//        itfImplogHeader.setDataContent(shipment);
        itfImplogHeader.setImportTime(new Date());
        insert(itfImplogHeader);

        String strData = shipment.replaceAll(" xmlns=\"http://xmlns.oracle.com/apps/otm/transmission/v6.4\"", "")
                .replaceAll(" xmlns:gtm=\"http://xmlns.oracle.com/apps/gtm/transmission/v6.4\" " +
                        "xmlns:otm=\"http://xmlns.oracle.com/apps/otm/transmission/v6.4\"", "")
                .replaceAll(" xsi:type=\"otm:TransactionHeaderType\"", "").replaceAll("otm:", "");
        try {
            OtmShipment otmShipment = OtmShipmentParse.parse(strData);
            if (Objects.isNull(otmShipment)) throw new BaseException("OTM指令数据转换错误！");
            otmShipment.setLogHeaderId(itfImplogHeader.getId());
            itfImplogHeader = updateLogByShipment(itfImplogHeader.getId(), otmShipment);
            otmShipment.setBoundType(itfImplogHeader.getType());
            logger.info("otmShipment:{}", otmShipment.toString());
            updateTaskWithNotice(otmShipment, null, null);
            updateLogImpStatus(itfImplogHeader.getId(), "1", "成功");
        } catch (Exception e) {
            updateLogImpStatus(itfImplogHeader.getId(), "0", e.getMessage());
            throw e;
        }
    }

    /**
     * 保存指令OTM
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateShipmentOTM(ShipmentDTO dto) {
        //checkParams(dto);
        HashMap<String, Long> logLineCache = Maps.newHashMap();
        ArrayList<String> inAdd = Lists.newArrayList();
        ArrayList<String> outAdd = Lists.newArrayList();
        List<ShipTaskDTO> taskDTOS = dto.getShipTaskDTOList();
        if (CollectionUtils.isNotEmpty(taskDTOS)) {
            for (ShipTaskDTO taskDTO : taskDTOS) {
                outAdd.add(taskDTO.getOriginLocationId());
                inAdd.add(taskDTO.getDestLocationId());
            }
        }
        // 出入仓库及orderType
        EntityWrapper<Storehouse> ewIn = new EntityWrapper<>();
        EntityWrapper<Storehouse> ewOut = new EntityWrapper<>();
        ewOut.eq("status", TableStatusEnum.STATUS_10.getCode())
                .in("code", outAdd);
        List<Storehouse> outHouses = storehouseService.selectList(ewOut);
        ewIn.eq("status", TableStatusEnum.STATUS_10.getCode())
                .in("code", inAdd);
        List<Storehouse> inHouses = storehouseService.selectList(ewIn);
        String orderType = acquireOrderType(outHouses, inHouses);
        //插入日志
        ItfImplogHeader header = getLogHeader(dto, logLineCache, orderType);
        new Thread(() -> {
            insert(header);
            itfImplogLineService.insertBatch(header.getItfImplogLineList());
        }).start();
        //构建otm数据
        OtmShipment otmShipment = getOtmShipment(dto, header, logLineCache, inHouses, outHouses);
        //构建对应任务及通知单
        updateTaskWithNotice(otmShipment, logLineCache, header.getId());
    }

    /**
     * 保存定时任务入库信息
     */
    @Override
    public void saveInboundDataFromTMSBySchedule() {
        if (logger.isInfoEnabled()) {
            logger.info("ItfImplogHeaderServiceImpl.info saveInboundDataFromTMSBySchedule start---->");
        }
        //获取时间戳-head表
        EntityWrapper<ItfImplogHeader> wrapper = new EntityWrapper<>();
        wrapper.eq("user_def9", SysSourceEnum.SCHEDULE.getName())
                .eq("source_system", SysSourceEnum.TMS_CREATE.getCode())
                .eq("type", TableStatusEnum.STATUS_10.getCode())
                .orderBy("gmt_create", false)
                .orderBy("id", false);
        Page<ItfImplogHeader> page = new Page<>(0, 1);
        List<ItfImplogHeader> headers = this.baseMapper.selectPage(page, wrapper);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String ts = getTimeStamp(headers, sdf);
        //调用tms获取定时数据
        String warehouse = inboundWarehouse;
        String result = null;
        String interfaceAddr = InterfaceAddrEnum.INBOUND_SCHECDULE_TMS.getAddress();
        try {
            result = callTms(ts, warehouse, interfaceAddr);
        } catch (Exception e) {
            logger.error("InboundSchedule.inboundDataFromTMSBySchedule error:", e);
        }
        if (StringUtils.isNotBlank(result)) {
            //如果本地存在改订单号已经更新的数据就跳过
            JSONObject parseObject = JSONObject.parseObject(result);
            String records = parseObject.getString("records");
            Boolean success = parseObject.getBoolean("success");
            String message = parseObject.getString("message");
            if (!success) {
                logger.error("InboundSchedule.inboundDataFromTMSBySchedule baseException:{}", message);
            } else {
                //定时抓取的数据都插入到接口表中-->在进行模糊查询车架号的时候  需要判断类型 获取数据的流程-->order-->rest方式修改-->http
                //后续同步接口表数据到业务order表中的时候需要绑定接口表的id 便于数据核实
                List<InboundNoticeFromTMSDTO> tmsDTOS = JSONObject.parseArray(records, InboundNoticeFromTMSDTO.class);
                ArrayList<ItfImplogHeader> implogHeaders = Lists.newArrayList();
                ArrayList<ItfImplogLine> implogLines = Lists.newArrayList();
                ArrayList<InboundNoticeHeader> noticeHeaders = Lists.newArrayList();
                ArrayList<InboundNoticeLine> noticeLines = Lists.newArrayList();
                String finalResult = result;
                HashMap<String, Long> whCache = Maps.newHashMap();
                tmsDTOS.stream().filter(v -> (!Objects.equals(v, null)
                        && (StringUtils.isNotBlank(v.getDest()))))
                        .forEach(bo -> {
                            ItfImplogHeader implogHeader = new ItfImplogHeader();
                            ItfImplogLine implogLine = new ItfImplogLine();
                            //设置仓库id
                            setInboundWhCache(bo, whCache);
                            saveInboundLog(finalResult, bo, implogHeader, implogLine, whCache);
                            implogHeaders.add(implogHeader);
                            implogLines.add(implogLine);
                            //重复校验
                            EntityWrapper<InboundNoticeLine> nlEW = new EntityWrapper<>();
                            nlEW.eq("store_house_id", whCache.get(bo.getDest()))
                                    .ne("status", TableStatusEnum.STATUS_50.getCode())
                                    .eq("lot_no1", bo.getVin());
                            int count = inboundNoticeLineService.selectCountWithHead(nlEW);
                            if (count < 1) {
                                //保存通知单数据
                                InboundNoticeHeader noticeHeader = new InboundNoticeHeader();
                                InboundNoticeLine noticeLine = new InboundNoticeLine();
                                saveInboundNoticeWithOutId(bo, implogHeader, implogLine, noticeHeader, noticeLine, whCache);
                                noticeHeader.setId(snowFlakeId.nextId());
                                noticeLine.setId(snowFlakeId.nextId());
                                noticeLine.setHeaderId(noticeHeader.getId());
                                noticeHeaders.add(noticeHeader);
                                noticeLines.add(noticeLine);
                            }
                        });
                insertLog(implogHeaders, implogLines);
                if (CollectionUtils.isNotEmpty(noticeHeaders)) {
                    inboundNoticeHeaderService.insertBatch(noticeHeaders);
                }
                if (CollectionUtils.isNotEmpty(noticeLines)) {
                    inboundNoticeLineService.insertBatch(noticeLines);
                }

            }
        }
    }

    /**
     * tms 更新入库数据 提供方WMS
     */
    @Override
    public ArrayList<Map<String, String>> updateInboundOrder(UpdateInboundFromTMSDTO interfaceDTO) {
        if (logger.isInfoEnabled()) {
            logger.info("ItfImplogHeaderServiceImpl.updateInboundOrder  param:{}", interfaceDTO);
        }
        ArrayList<Map<String, String>> result = Lists.newArrayList();
        //记录接口数据日志
        if (interfaceDTO == null) {
            throw new BaseException("参数不能为空!");
        }
        String orderDto = interfaceDTO.getUpdateOrderDto();
        String key = interfaceDTO.gethKey();
        List<InboundNoticeFromTMSDTO> orderDTOS = JSONObject.parseArray(orderDto, InboundNoticeFromTMSDTO.class);
        if (StringUtils.isBlank(key)) {
            throw new BaseException("接口请求key不能为空!");
        }
        if (!properties.getEncodeKey().equals(key)) {
            throw new BaseException("请输入正确的key");
        }
        if (CollectionUtils.isNotEmpty(orderDTOS)) {
            ArrayList<ItfImplogHeader> implogHeaders = Lists.newArrayList();
            ArrayList<ItfImplogLine> implogLines = Lists.newArrayList();
            ArrayList<InboundNoticeHeader> insertHeaders = Lists.newArrayList();
            ArrayList<InboundNoticeHeader> updateHeaders = Lists.newArrayList();
            ArrayList<InboundNoticeLine> insertLines = Lists.newArrayList();
            ArrayList<InboundNoticeLine> updateLines = Lists.newArrayList();
            //保存日志
            HashMap<String, Long> whCache = Maps.newHashMap();
            orderDTOS.stream().filter(v -> (!Objects.equals(v, null)
                    && StringUtils.isNotBlank(v.getDest())))
                    .forEach(bo -> {
                        //保存日志
                        ItfImplogHeader implogHeader = new ItfImplogHeader();
                        ItfImplogLine implogLine = new ItfImplogLine();
                        //设置仓库id
                        setInboundWhCache(bo, whCache);
                        saveInboundLog(JSONObject.toJSONString(interfaceDTO),
                                bo,
                                implogHeader,
                                implogLine,
                                whCache);
                        implogHeader.setUserDef8(bo.getOd_status());
                        implogHeader.setUserDef9(SysSourceEnum.REST_MODIFY.getName());
                        implogLine.setUserDef8(bo.getOd_status());
                        implogLine.setUserDef9(SysSourceEnum.REST_MODIFY.getName());
                        implogHeaders.add(implogHeader);
                        implogLines.add(implogLine);
                        //根据子订单号找到原数据
                        Wrapper<InboundNoticeLine> wrapper = new EntityWrapper<>();
                        wrapper.eq("line_source_key", bo.getZorderno())
                                .eq("line_source_no", bo.getOrderno());
                        List<InboundNoticeLine> inboundNoticeLines = inboundNoticeLineService.selectList(wrapper);
                        if (CollectionUtils.isEmpty(inboundNoticeLines)) {
                            //修改数据但是定时任务还未执行查询到数据 需要新增
                            InboundNoticeHeader noticeHeader = new InboundNoticeHeader();
                            InboundNoticeLine noticeLine = new InboundNoticeLine();
                            saveInboundNoticeWithOutId(bo, implogHeader, implogLine, noticeHeader, noticeLine, whCache);
                            noticeHeader.setUserCreate(SysSourceEnum.REST_MODIFY.getName());
                            noticeHeader.setUserModified(SysSourceEnum.REST_MODIFY.getName());
                            noticeHeader.setId(snowFlakeId.nextId());
                            noticeLine.setId(snowFlakeId.nextId());
                            noticeLine.setHeaderId(noticeHeader.getId());
                            if (SysSourceEnum.DELETE_TYPE.getName().equals(bo.getOd_status())) {
                                noticeLine.setStatus(TableStatusEnum.STATUS_50.getCode());
                                noticeHeader.setStatus(TableStatusEnum.STATUS_50.getCode());
                            }
                            insertHeaders.add(noticeHeader);
                            insertLines.add(noticeLine);
                        } else if (inboundNoticeLines.size() > 1) {
                            throw new BaseException("子订单号:" + bo.getZorderno() + "存在多条记录");
                        } else {
                            //更新通知单 zorderno 判断唯一性
                            InboundNoticeLine noticeLine = inboundNoticeLines.get(0);
                            InboundNoticeHeader noticeHeader = inboundNoticeHeaderService.selectById(noticeLine.getHeaderId());
                            saveInboundNoticeWithOutId(bo,
                                    implogHeader,
                                    implogLine,
                                    noticeHeader,
                                    noticeLine,
                                    whCache);
                            noticeHeader.setUserModified(SysSourceEnum.REST_MODIFY.getName());
                            noticeHeader.setGmtModified(null);
                            if (SysSourceEnum.DELETE_TYPE.getName().equals(bo.getOd_status())) {
                                noticeLine.setStatus(TableStatusEnum.STATUS_50.getCode());
                                noticeHeader.setStatus(TableStatusEnum.STATUS_50.getCode());
                            }
                            noticeLine.setGmtModified(null);
                            updateLines.add(noticeLine);
                            updateHeaders.add(noticeHeader);
                        }
                        //已收货或者已入库不能进行更新
                        Map<String, String> resultMap = Maps.newHashMap();
                        resultMap.put("vin", bo.getVin());
                        resultMap.put("msg", "更新成功!");
                        result.add(resultMap);
                    });
            //新增日志
            insertLog(implogHeaders, implogLines);

            if (CollectionUtils.isNotEmpty(insertHeaders)) {
                inboundNoticeHeaderService.insertBatch(insertHeaders);
            }
            if (CollectionUtils.isNotEmpty(insertLines)) {
                inboundNoticeLineService.insertBatch(insertLines);
            }
            if (CollectionUtils.isNotEmpty(updateHeaders)) {
                inboundNoticeHeaderService.updateBatchById(updateHeaders);
            }
            if (CollectionUtils.isNotEmpty(updateLines)) {
                inboundNoticeLineService.updateBatchById(updateLines);
            }
            return result;
        }
        return null;
    }

    private void insertLog(ArrayList<ItfImplogHeader> implogHeaders, ArrayList<ItfImplogLine> implogLines) {
        new Thread(() -> {
            if (CollectionUtils.isNotEmpty(implogHeaders)) {
                insertBatch(implogHeaders);
            }
            if (CollectionUtils.isNotEmpty(implogLines)) {
                itfImplogLineService.insertBatch(implogLines);
            }
        }).start();
    }


    /**
     * 出库通知单定时任务
     */
    @Override
    public void saveOutboundDataFromTMSBySchedule() {
        if (logger.isInfoEnabled()) {
            logger.info("ItfImplogHeaderServiceImpl.saveOutboundDataFromTMSBySchedule start ---->");
        }
        //时间戳   接口地址  仓库名称
        //获取时间戳-head表
        EntityWrapper<ItfImplogHeader> wrapper = new EntityWrapper<>();
        wrapper.eq("user_def9", SysSourceEnum.SCHEDULE.getName())
                .eq("source_system", SysSourceEnum.TMS_CREATE.getCode())
                .eq("type", TableStatusEnum.STATUS_20.getCode())
                .orderBy("gmt_create", false)
                .orderBy("id", false);
        Page<ItfImplogHeader> page = new Page<>(0, 1);
        List<ItfImplogHeader> headers = this.baseMapper.selectPage(page, wrapper);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String ts = getTimeStamp(headers, sdf);
        //调用tms获取定时数据
        String warehouse = outboundWarehouse;
        String interfaceAddr = InterfaceAddrEnum.SHIPMENT_SCHEDULE_TMS.getAddress();
        String result = null;
        try {
            result = callTms(ts, warehouse, interfaceAddr);
        } catch (Exception e) {
            logger.error("InboundSchedule.saveOutboundDataFromTMSBySchedule callTMS error:{}", e);
        }
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            String msg = jsonObject.getString("message");
            String records = jsonObject.getString("records");
            Boolean success = jsonObject.getBoolean("success");
            if (!success) {
                logger.error("ItfImplogHeaderServiceImpl.saveOutboundDataFromTMSBySchedule baseException:{}", msg);
            } else {
                List<OutboundNoticeFromTMSDTO> fromTMSDTOS = JSONArray.parseArray(records, OutboundNoticeFromTMSDTO.class);
                ArrayList<ItfImplogHeader> implogHeaders = Lists.newArrayList();
                ArrayList<ItfImplogLine> implogLines = Lists.newArrayList();
                ArrayList<OutboundNoticeHeader> noticeHeaders = Lists.newArrayList();
                ArrayList<OutboundNoticeLine> noticeLines = Lists.newArrayList();
                String finalResult = result;
                HashMap<String, Long> whCache = Maps.newHashMap();
                fromTMSDTOS.stream()
                        .filter(v -> !Objects.isNull(v) && StringUtils.isNotBlank(v.getOrigin()))
                        .forEach(dto -> {
                            //记录日志
                            ItfImplogHeader implogHeader = new ItfImplogHeader();
                            ItfImplogLine implogLine = new ItfImplogLine();
                            //设置仓库id
                            setOutboundCache(whCache, dto);
                            saveOutboundLog(finalResult, dto, implogHeader, implogLine, whCache);
                            implogHeaders.add(implogHeader);
                            implogLines.add(implogLine);
                            //重复校验
                            EntityWrapper<OutboundNoticeLine> nlEW = new EntityWrapper<>();
                            nlEW.eq("lot_no1", dto.getVin())
                                    .ne("status", TableStatusEnum.STATUS_50.getCode())
                                    .eq("store_house_id", whCache.get(dto.getOrigin()));
                            int count = outboundNoticeLineService.selectCountWithHeader(nlEW);
                            if (count < 1) {
                                //保存数据
                                OutboundNoticeHeader noticeHeader = new OutboundNoticeHeader();
                                OutboundNoticeLine noticeLine = new OutboundNoticeLine();
                                saveOutboundNoticeWithOutId(dto,
                                        implogHeader,
                                        implogLine,
                                        noticeHeader,
                                        noticeLine,
                                        whCache);
                                noticeHeader.setId(snowFlakeId.nextId());
                                noticeLine.setId(snowFlakeId.nextId());
                                noticeLine.setHeaderId(noticeHeader.getId());
                                noticeHeaders.add(noticeHeader);
                                noticeLines.add(noticeLine);
                            }
                        });
                insertLog(implogHeaders, implogLines);
                if (CollectionUtils.isNotEmpty(noticeHeaders)) {
                    outboundNoticeHeaderService.insertBatch(noticeHeaders);
                }
                if (CollectionUtils.isNotEmpty(noticeLines)) {
                    outboundNoticeLineService.insertBatch(noticeLines);
                }
            }
        }
    }

    /**
     * 接收mq推送更新出库通知单数据
     * 2018-6-28 增加字段zorderno 用于确定更新数据
     */
    @Override
    public void updateOutboundNoticeFromTMS(String message) {
        if (logger.isInfoEnabled()) {
            logger.info("ItfImplogHeaderServiceImpl.updateOutboundNoticeFromTMS start ---->");
        }
        //
        JSONObject object = JSON.parseObject(message);
        String shipno = object.getString("shipno");  //指令号
        String supplier = object.getString("supplier");
        String vehicle = object.getString("vehicle");//板车牌号
        String timestamp = object.getString("timeStamp");//用于解决mq乱序的时间戳
        //指令肯定是必须的
        List<OutboundNoticeFromTMSDTO> routeList = JSON.parseArray(object.getString("route"), OutboundNoticeFromTMSDTO.class);//获取json对象数组格式
        if (StringUtils.isBlank(timestamp)) {
            logger.error("ItfImplogHeaderServiceImpl.updateOutboundNoticeFromTMS error timeStamp is null");
            throw new BaseException("mq时间戳为空");
        }
        ArrayList<ItfImplogHeader> implogHeaders = Lists.newArrayList();
        ArrayList<ItfImplogLine> implogLines = Lists.newArrayList();
        ArrayList<OutboundNoticeHeader> insertHeaders = Lists.newArrayList();
        ArrayList<OutboundNoticeHeader> updateHeaders = Lists.newArrayList();
        ArrayList<OutboundNoticeLine> insertLines = Lists.newArrayList();
        ArrayList<OutboundNoticeLine> updateLines = Lists.newArrayList();
        //先删掉原来整个指令下的出库信息-->根据新的mq消息新增或者修改为正常状态
        HashMap<String, Date> timeMap = Maps.newHashMap();
        HashMap<Long, String> lineStatusMap = Maps.newHashMap();
        HashMap<Long, String> headStatusMap = Maps.newHashMap();
        EntityWrapper<OutboundNoticeLine> outWrapper = new EntityWrapper<>();
        outWrapper.eq("line_source_no", shipno);
        List<OutboundNoticeLine> noticeLines = outboundNoticeLineService.selectList(outWrapper);
        if (CollectionUtils.isNotEmpty(noticeLines)) {
            noticeLines.forEach(v -> {
                //时间戳要大才更新 -- 日志时间戳
                ItfImplogLine implogLine = itfImplogLineService.selectById(v.getLogLineId());
                if (implogLine != null &&
                        StringUtils.isNotBlank(implogLine.getUserDef7())) {
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    try {
                        Date oldTime = sdf.parse(implogLine.getUserDef7());
                        Date mqTime = sdf.parse(timestamp);
                        timeMap.put("oldTime", oldTime);
                        timeMap.put("mqTime", mqTime);
                        if (oldTime.before(mqTime)) {
                            lineStatusMap.put(v.getId(), v.getStatus());
                            v.setStatus(TableStatusEnum.STATUS_50.getCode());
                            v.setGmtModified(null);
                            //更新head
                            OutboundNoticeHeader noticeHeader = outboundNoticeHeaderService.selectById(v.getHeaderId());
                            headStatusMap.put(noticeHeader.getId(), noticeHeader.getStatus());
                            noticeHeader.setUserModified(SysSourceEnum.MQ.getName());
                            noticeHeader.setGmtModified(null);
                            noticeHeader.setStatus(TableStatusEnum.STATUS_50.getCode());
                            updateHeaders.add(noticeHeader);
                        }
                    } catch (ParseException e) {
                        logger.error("ItfImplogHeaderServiceImpl.updateOutboundNoticeFromTMS ParseException:", e);
                    }
                }
            });
            if (CollectionUtils.isNotEmpty(noticeLines)) {
                outboundNoticeLineService.updateBatchById(noticeLines);
                noticeLines.clear();
            }
            if (CollectionUtils.isNotEmpty(updateHeaders)) {
                outboundNoticeHeaderService.updateBatchById(updateHeaders);
                updateHeaders.clear();
            }
        }
        //保存日志  仍需要判断时间戳
        if (CollectionUtils.isNotEmpty(routeList)) {
            for (OutboundNoticeFromTMSDTO mqDTO : routeList) {
                mqDTO.setTimestamp(timestamp);
                mqDTO.setShipno(shipno);
                mqDTO.setSupplier(supplier);
                mqDTO.setVehicle(vehicle);
            }
            HashMap<String, Long> whCache = Maps.newHashMap();
            routeList.stream()
                    .filter(v -> (!Objects.isNull(v) && StringUtils.isNotBlank(v.getOrigin())))
                    .forEach(dto -> {
                        //保存日志
                        ItfImplogHeader implogHeader = new ItfImplogHeader();
                        ItfImplogLine implogLine = new ItfImplogLine();
                        //获取仓库id
                        setOutboundCache(whCache, dto);
                        saveOutboundLog(message, dto, implogHeader, implogLine, whCache);
                        implogHeader.setUserDef8(SysSourceEnum.MODIFY_TYPE.getName());
                        implogHeader.setUserDef9(SysSourceEnum.MQ.getName());
                        implogLine.setUserDef8(SysSourceEnum.MODIFY_TYPE.getName());
                        implogLine.setUserDef9(SysSourceEnum.MQ.getName());
                        implogHeaders.add(implogHeader);
                        implogLines.add(implogLine);
                        //根据子订单号找到原数据
                        if (timeMap.get("oldTime") == null ||
                                timeMap.get("oldTime").before(timeMap.get("mqTime"))) {
                            Wrapper<OutboundNoticeLine> wrapper = new EntityWrapper<>();
                            wrapper.eq("line_source_key", dto.getZorderno())
                                    .eq("line_source_no", dto.getShipno());
                            List<OutboundNoticeLine> outboundNoticeLines = outboundNoticeLineService.selectList(wrapper);
                            if (CollectionUtils.isEmpty(outboundNoticeLines)) {
                                //修改数据但是定时任务还未执行查询到数据 需要新增
                                OutboundNoticeHeader noticeHeader = new OutboundNoticeHeader();
                                OutboundNoticeLine noticeLine = new OutboundNoticeLine();
                                saveOutboundNoticeWithOutId(dto,
                                        implogHeader,
                                        implogLine,
                                        noticeHeader,
                                        noticeLine,
                                        whCache);
                                noticeHeader.setUserCreate(SysSourceEnum.MQ.getName());
                                noticeHeader.setUserModified(SysSourceEnum.MQ.getName());
                                noticeHeader.setId(snowFlakeId.nextId());
                                noticeLine.setId(snowFlakeId.nextId());
                                noticeLine.setHeaderId(noticeHeader.getId());
                                insertHeaders.add(noticeHeader);
                                insertLines.add(noticeLine);
                            } else if (outboundNoticeLines.size() > 1) {
                                throw new BaseException("子订单号:" + dto.getZorderno() + "存在多条记录");
                            } else {
                                //更新通知单 zorderno 判断唯一性 更新状态
                                OutboundNoticeLine noticeLine = outboundNoticeLines.get(0);
                                OutboundNoticeHeader noticeHeader = outboundNoticeHeaderService.selectById(noticeLine.getHeaderId());
                                saveOutboundNoticeWithOutId(dto,
                                        implogHeader,
                                        implogLine,
                                        noticeHeader,
                                        noticeLine,
                                        whCache);
                                noticeLine.setStatus(lineStatusMap.get(noticeLine.getId()));
                                noticeLine.setGmtModified(null);
                                noticeHeader.setUserModified(SysSourceEnum.MQ.getName());
                                noticeHeader.setGmtModified(null);
                                noticeHeader.setStatus(headStatusMap.get(noticeHeader.getId()));
                                updateLines.add(noticeLine);
                                updateHeaders.add(noticeHeader);
                            }
                        }
                    });

        } else {
            //删除指令数据 保存日志
            saveLogWithOutRouteList(message, shipno, timestamp, implogHeaders, implogLines);
        }
        //新增日志
        insertLog(implogHeaders, implogLines);

        if (CollectionUtils.isNotEmpty(insertHeaders)) {
            outboundNoticeHeaderService.insertBatch(insertHeaders);
        }
        if (CollectionUtils.isNotEmpty(insertLines)) {
            outboundNoticeLineService.insertBatch(insertLines);
        }
        if (CollectionUtils.isNotEmpty(updateHeaders)) {
            outboundNoticeHeaderService.updateBatchById(updateHeaders);
        }
        if (CollectionUtils.isNotEmpty(updateLines)) {
            outboundNoticeLineService.updateBatchById(updateLines);
        }
    }

    private void setOutboundCache(HashMap<String, Long> whCache, OutboundNoticeFromTMSDTO dto) {
        //设置仓库id
        Wrapper<Storehouse> wp = new EntityWrapper<>();
        wp.eq("name", dto.getOrigin())
                .eq("status", TableStatusEnum.STATUS_10.getCode());
        if (whCache.get(dto.getOrigin()) == null) {
            List<Storehouse> storehouses = storehouseService.selectList(wp);
            if (CollectionUtils.isNotEmpty(storehouses)) {
                whCache.put(dto.getOrigin(), storehouses.get(0).getId());
            } else {
                whCache.put(dto.getOrigin(), 0L);
            }
        }
    }

    private void setInboundWhCache(InboundNoticeFromTMSDTO bo, HashMap<String, Long> whCache) {
        Wrapper<Storehouse> shwp = new EntityWrapper<>();
        shwp.eq("name", bo.getDest())
                .eq("status", TableStatusEnum.STATUS_10.getCode());
        if (whCache.get(bo.getDest()) == null) {
            List<Storehouse> storehouses = storehouseService.selectList(shwp);
            if (CollectionUtils.isNotEmpty(storehouses)) {
                whCache.put(bo.getDest(), storehouses.get(0).getId());
            } else {
                whCache.put(bo.getDest(), 0L);
            }
        }
    }

    private void saveLogWithOutRouteList(String message,
                                         String shipno,
                                         String timestamp,
                                         ArrayList<ItfImplogHeader> implogHeaders,
                                         ArrayList<ItfImplogLine> implogLines) {
        ItfImplogHeader implogHeader = new ItfImplogHeader();
        ItfImplogLine implogLine = new ItfImplogLine();
        implogHeader.setId(snowFlakeId.nextId());
        implogHeader.setUserDef8(SysSourceEnum.MODIFY_TYPE.getName());
        implogHeader.setUserDef9(SysSourceEnum.MQ.getName());
        implogHeader.setSourceSystem(SysSourceEnum.TMS_CREATE.getCode());
        implogHeader.setType(TableStatusEnum.STATUS_20.getCode());
        implogHeader.setUom(UomEnum.TAI.getName());
        implogHeader.setStatus(TableStatusEnum.STATUS_10.getCode());
        implogHeader.setLineCount(1);
        implogHeader.setImportTime(new Date());
        implogHeader.setDataContent(message);
        implogLine.setUom(UomEnum.TAI.getName());

        implogLine.setId(snowFlakeId.nextId());
        implogHeader.setUserDef8(SysSourceEnum.MODIFY_TYPE.getName());
        implogHeader.setUserDef9(SysSourceEnum.MQ.getName());
        implogLine.setUserDef8(SysSourceEnum.MODIFY_TYPE.getName());
        implogLine.setUserDef9(SysSourceEnum.MQ.getName());
        implogLine.setHeaderId(implogHeader.getId());
        implogLine.setLineSourceNo(shipno); //指令号
        implogLine.setUserDef7(timestamp); //时间戳--防止乱序消费
        implogLine.setUserDef8(SysSourceEnum.NORMAL_TYPE.getName());
        implogLine.setUserDef9(SysSourceEnum.MQ.getName());
        implogLine.setExpectQty(new BigDecimal(1));
        implogHeaders.add(implogHeader);
        implogLines.add(implogLine);
    }

    private String getTimeStamp(List<ItfImplogHeader> headers, SimpleDateFormat sdf) {
        String ts;
        if (CollectionUtils.isEmpty(headers)) {
            Calendar calendar = new GregorianCalendar();
            calendar.setTime(new Date());
            calendar.add(Calendar.DAY_OF_YEAR, -5);
            ts = sdf.format(calendar.getTime());
        } else {
            ts = sdf.format(headers.get(0).getGmtCreate());
        }
        return ts;
    }

    private void saveInboundNoticeWithOutId(InboundNoticeFromTMSDTO bo,
                                            ItfImplogHeader implogHeader,
                                            ItfImplogLine implogLine,
                                            InboundNoticeHeader nh,
                                            InboundNoticeLine nl, HashMap<String, Long> whCache) {
        nh.setNoticeNo(iBusinessDocNumberService.getInboundNoticeNo());
        nh.setLogHeaderId(implogHeader.getId());
        nh.setStatus(TableStatusEnum.STATUS_10.getCode());
        nh.setExpectSumQty(new BigDecimal(1));
        nh.setInboundSumQty(new BigDecimal(0));
        nh.setOwnerId(bo.getCustomer());
        nh.setStoreHouseId(whCache.get(bo.getDest()) == null ? 0L : whCache.get(bo.getDest()));
        nh.setOwnerOrderNo(bo.getCustOrderno());
        nh.setOrderDate(new Date());
        nh.setSourceNo(bo.getOrderno());
        nh.setLineCount(1);
        nh.setUom(UomEnum.TAI.getName());
        nh.setUserCreate(SysSourceEnum.SCHEDULE.getName());
        nh.setUserModified(SysSourceEnum.SCHEDULE.getName());

        nl.setHeaderId(nh.getId());
        nl.setLogLineId(implogLine.getId());
        nl.setExpectQty(new BigDecimal(1));
        nl.setInboundQty(new BigDecimal(0));
        nl.setOwnerOrderNo(bo.getCustOrderno());
        nl.setOwnerId(bo.getCustomer());
        nl.setLineSourceNo(bo.getOrderno());
        nl.setLineSourceKey(bo.getZorderno());//子订单号
        nl.setMaterielId(bo.getStyle());
        nl.setUom(MeasureUnit.TAI);
        nl.setMaterielCode(bo.getStyleId());
        nl.setMaterielName(bo.getStyleDesc());
        nl.setLotNo1(bo.getVin());
        nl.setStatus(TableStatusEnum.STATUS_10.getCode());
        nh.setUserCreate(SysSourceEnum.SCHEDULE.getName());
        nh.setUserModified(SysSourceEnum.SCHEDULE.getName());
    }

    private void saveInboundLog(String finalResult,
                                InboundNoticeFromTMSDTO dto,
                                ItfImplogHeader ilh,
                                ItfImplogLine ill,
                                HashMap<String, Long> whCache) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        ilh.setId(snowFlakeId.nextId());
        //ilh.setOwnerId();
        ilh.setSourceNo(dto.getOrderno());
        ilh.setOwnerId(dto.getCustomer());
        ilh.setOwnerOrderNo(dto.getCustOrderno());
        ilh.setSourceSystem(SysSourceEnum.TMS_CREATE.getCode());
        ilh.setUom(UomEnum.TAI.getName());
        ilh.setRecvHouseName(dto.getDest());
        ilh.setRecvHouseId(String.valueOf(whCache.get(dto.getDest())));
        ilh.setType(TableStatusEnum.STATUS_10.getCode());
        ilh.setStatus(TableStatusEnum.STATUS_10.getCode());
        ilh.setImportStatus(TableStatusEnum.STATUS_10.getCode());
        ilh.setLineCount(1);
        ilh.setExpectSumQty(BigDecimal.ONE);
        ilh.setImportTime(new Date());
//        ilh.setDataContent(finalResult);
        ilh.setUserDef1(dto.getCustShipno());//客户运单号
        ilh.setUserDef2(dto.getOrigin());//起运地
        ilh.setUserDef3(dto.getDest());//目的地
        ilh.setUserDef8(SysSourceEnum.NORMAL_TYPE.getName());
        ilh.setUserDef9(SysSourceEnum.SCHEDULE.getName());

        ill.setId(snowFlakeId.nextId());
        ill.setHeaderId(ilh.getId());
        ill.setOwnerId(dto.getCustomer());
        ill.setOwnerOrderNo(dto.getCustOrderno());
        ill.setUom(UomEnum.TAI.getName());
        ill.setLineSourceNo(dto.getOrderno());
        ill.setLineSourceKey(dto.getZorderno()); //子订单号
        ill.setMaterielId(dto.getStyle());
        ill.setUom(MeasureUnit.TAI);
        ill.setMaterielCode(dto.getStyleId());
        ill.setMaterielName(dto.getStyleDesc());
        ill.setLotNo1(dto.getVin());
//        ill.setLotNo4(dto.getStyle());
        ill.setUserDef1(dto.getFactory_whno());
        ill.setUserDef2(dto.getStocktransfer()); //是否移库标识
        ill.setUserDef7(sdf.format(new Date()));//时间戳
        ill.setUserDef8(SysSourceEnum.NORMAL_TYPE.getName());
        ill.setUserDef9(SysSourceEnum.SCHEDULE.getName());
        ill.setExpectQty(new BigDecimal(1));
    }

    private void saveOutboundNoticeWithOutId(OutboundNoticeFromTMSDTO dto,
                                             ItfImplogHeader implogHeader,
                                             ItfImplogLine implogLine,
                                             OutboundNoticeHeader nh,
                                             OutboundNoticeLine nl,
                                             HashMap<String, Long> whCache) {
        nh.setNoticeNo(iBusinessDocNumberService.getOutboundNoticeNo());

        nh.setLogHeaderId(implogHeader.getId());
        nh.setStoreHouseId(whCache.get(dto.getOrigin()) == null ? 0L : whCache.get(dto.getOrigin()));
        nh.setStatus(TableStatusEnum.STATUS_10.getCode());
        nh.setExpectSumQty(new BigDecimal(1));
        nh.setOwnerId(dto.getCustomer());
        nh.setOwnerOrderNo(dto.getOrderno());
        nh.setOutboundSumQty(new BigDecimal(0));
        nh.setSourceNo(dto.getOrderno()); // 系统订单号
        nh.setSourceKey(dto.getCustshipno());  //客户运单号
        nh.setCarrierName(dto.getSupplier());
        nh.setPlateNumber(dto.getVehicle());
        nh.setDriverName(dto.getDriver());
        nh.setDriverPhone(dto.getMobile());
        nh.setLineCount(1);
        nh.setUom(UomEnum.TAI.getName());
        nh.setGenMethod(TableStatusEnum.STATUS_30.getCode());
        nh.setUserCreate(SysSourceEnum.SCHEDULE.getName());
        nh.setUserModified(SysSourceEnum.SCHEDULE.getName());

        nl.setHeaderId(nh.getId());
        nl.setLogLineId(implogLine.getId());
        nl.setExpectQty(new BigDecimal(1));
        nl.setOutboundQty(new BigDecimal(0));
        nl.setLineSourceNo(dto.getShipno()); //指令号
        nl.setOwnerId(dto.getCustomer());
        nl.setOwnerOrderNo(dto.getOrderno());
        nl.setLineSourceKey(dto.getZorderno());
        nl.setMaterielId(dto.getStyle());
        nl.setUom(MeasureUnit.TAI);
        nl.setMaterielCode(dto.getStyleID());
        nl.setMaterielName(dto.getStyleDesc());
        nl.setLotNo1(dto.getVin());
        nl.setStatus(TableStatusEnum.STATUS_10.getCode());
    }

    private void saveOutboundLog(String finalResult,
                                 OutboundNoticeFromTMSDTO dto,
                                 ItfImplogHeader ilh,
                                 ItfImplogLine ipl,
                                 HashMap<String, Long> whCache) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        ilh.setId(snowFlakeId.nextId());
        ilh.setOwnerId(dto.getCustomer());
        ilh.setOwnerOrderNo(dto.getOrderno());
        ilh.setSourceNo(dto.getOrderno()); //系统订单号
        ilh.setSourceKey(dto.getCustshipno()); //客户运单号
        ilh.setRecvHouseId(String.valueOf(whCache.get(dto.getOrigin())));
        ilh.setCarrierName(dto.getSupplier());
        ilh.setPlateNumber(dto.getVehicle());
        ilh.setDriverName(dto.getDriver());
        ilh.setDriverPhone(dto.getMobile());
        ilh.setDeliveryHouseId(String.valueOf(whCache.get(dto.getOrigin())));
        ilh.setExpectSumQty(new BigDecimal(1));
        ilh.setDeliveryHouseName(dto.getOrigin());
        ilh.setImportTime(new Date());
//        ilh.setDataContent(finalResult);
        ilh.setUom(UomEnum.TAI.getName());
        ilh.setLineCount(1);
        ilh.setSourceSystem(SysSourceEnum.TMS_CREATE.getCode());
        ilh.setType(TableStatusEnum.STATUS_20.getCode());
        ilh.setStatus(TableStatusEnum.STATUS_10.getCode());
        ilh.setUserDef8(SysSourceEnum.NORMAL_TYPE.getName());
        ilh.setUserDef9(SysSourceEnum.SCHEDULE.getName());

        ipl.setId(snowFlakeId.nextId());
        ipl.setHeaderId(ilh.getId());
        ipl.setOwnerId(dto.getCustomer());
        ipl.setOwnerOrderNo(dto.getOrderno());
        ipl.setLineSourceKey(dto.getZorderno());//子订单号
        ipl.setLineSourceNo(dto.getShipno()); //指令号
        ipl.setMaterielId(dto.getStyle());
        ipl.setUom(MeasureUnit.TAI);
        ipl.setMaterielCode(dto.getStyleID());
        ipl.setMaterielName(dto.getStyleDesc());
        ipl.setLotNo1(dto.getVin());
//        ipl.setLotNo4(dto.getStyle());
        ipl.setUserDef0(dto.getDtship());
        ipl.setUserDef1(dto.getOrderno());//系统订单号
        ipl.setUserDef2(dto.getRoute_end());//指令目的地
        ipl.setUserDef3(dto.getOrigin());//起运地
        ipl.setUserDef4(dto.getDest());//货运地
        ipl.setUserDef7(StringUtils.isBlank(dto.getTimestamp()) ?
                sdf.format(new Date()) : dto.getTimestamp()); //时间戳--防止乱序消费
        ipl.setUserDef8(SysSourceEnum.NORMAL_TYPE.getName());
        ipl.setUserDef9(SysSourceEnum.SCHEDULE.getName());
        ipl.setExpectQty(new BigDecimal(1));
    }

    /**
     * 调用 tms 的接口  查询入库数据
     */
    private String callTms(String timestamp,
                           String warehouse,
                           String interfaceAddr) throws Exception {
        // 构建URL
        String url = properties.getFetchInboundFromTMSUrl();
        Integer time = properties.getSocketTimeOut();
        String encode_key = properties.getEncodeKey();
        Map<String, Object> map = new HashMap<>();
        Map<String, Object> headerMap = new HashMap<>();
        headerMap.put("encode-key", encode_key);
        url = url + interfaceAddr;
        map.put("timestamp", timestamp);
        map.put("warehouse", warehouse);
        if (InterfaceAddrEnum.SHIPMENT_SCHEDULE_TMS.getAddress().equals(interfaceAddr)) {
            map.put("type", OpConstant.OUT_TYPE);
        }
        return HttpRequestUtil.sendHttpPost(url, headerMap, map, time);
    }


    private void updateTaskWithNotice(OtmShipment otmShipment,
                                      HashMap<String, Long> logLineCache,
                                      Long logHeadId) {
        if ("IU".equals(otmShipment.getTransactionCode())) {
            //指令号是否存在
            Wrapper<OtmShipment> otmShipmentWrapper = new EntityWrapper<>();
            otmShipmentWrapper.eq("shipment_gid", otmShipment.getShipmentGid());
            otmShipmentWrapper.ne("status", TableStatusEnum.STATUS_50.getCode());
            Integer count = otmShipmentService.selectCount(otmShipmentWrapper);
            if (count < 1) {
                shipmentInsert(otmShipment);
            }
        } else if ("R".equals(otmShipment.getTransactionCode())) {
            //得到原调度指令
            OtmShipment otmShipmentOld = getOldShipment(otmShipment);
            if (Objects.isNull(otmShipmentOld)) {
                shipmentInsert(otmShipment);
            } else {
                shipmentUpdate(otmShipment,
                        otmShipmentOld,
                        logLineCache,
                        logHeadId);
            }
        } else if ("RC".equals(otmShipment.getTransactionCode())) {
            OtmShipment oldShipment = getOldShipment(otmShipment);
            shipmentDelete(otmShipment, oldShipment);
        } else {
            logger.error("推送指令类型:{},不支持此类型操作", otmShipment.getTransactionCode());
        }
    }

    private OtmShipment getOldShipment(OtmShipment otmShipment) {
        Wrapper<OtmShipment> ew = new EntityWrapper<>();
        ew.eq("shipment_gid", otmShipment.getShipmentGid())
                .notIn("status", TableStatusEnum.STATUS_50.getCode())
                .orderBy("gmt_create", false)
                .orderBy("id", false);
        return otmShipmentService.selectOne(ew);
    }

    /**
     * 指令新增时的处理
     */
    private void shipmentInsert(OtmShipment otmShipment) {

        otmShipmentService.insertShipment(otmShipment);//保存指令

        if (otmShipment.getShipmentType().equals(OtmShipmentType.PICK_UP)) { //提车指令
            buildOpTask(otmShipment);
        }
        if (TableStatusEnum.STATUS_10.getCode().equals(otmShipment.getBoundType())) {
            List<String> houseCodeList = new ArrayList<>();
            for (OtmOrderRelease otmOrderRelease : otmShipment.getOtmOrderReleaseList()) {
                houseCodeList.add(otmOrderRelease.getDestLocationGid());
            }
            EntityWrapper<Storehouse> ew = new EntityWrapper<>();
            ew.in("code", houseCodeList);
            List<Storehouse> storehouseList = storehouseService.selectList(ew);

            for (Storehouse storehouse : storehouseList) {
                List<OtmOrderRelease> otmOrderReleaseList = listInboundRelease(storehouse,
                        otmShipment.getOtmOrderReleaseList());
                insertInboundNotice(otmShipment, otmOrderReleaseList);
            }
        } else if (TableStatusEnum.STATUS_20.getCode().equals(otmShipment.getBoundType())) {
            //得到需出库的仓库
            List<String> houseCodeList = new ArrayList<>();
            for (OtmOrderRelease otmOrderRelease : otmShipment.getOtmOrderReleaseList()) {
                houseCodeList.add(otmOrderRelease.getOriginLocationGid());
            }
            EntityWrapper<Storehouse> ew = new EntityWrapper<>();
            ew.in("code", houseCodeList);
            List<Storehouse> storehouseList = storehouseService.selectList(ew);
            for (Storehouse storehouse : storehouseList) {
                List<OtmOrderRelease> otmOrderReleaseList = listOutboundRelease(storehouse,
                        otmShipment.getOtmOrderReleaseList());
                insertOutboundNotice(otmShipment, otmOrderReleaseList);
            }
        } else if (TableStatusEnum.STATUS_30.getCode().equals(otmShipment.getBoundType())) {
            List<String> outHouseCodeList = new ArrayList<>();
            List<String> inHouseCodeList = new ArrayList<>();
            for (OtmOrderRelease otmOrderRelease : otmShipment.getOtmOrderReleaseList()) {
                outHouseCodeList.add(otmOrderRelease.getOriginLocationGid());
                inHouseCodeList.add(otmOrderRelease.getDestLocationGid());
            }
            EntityWrapper<Storehouse> outEw = new EntityWrapper<>();
            outEw.in("code", outHouseCodeList);

            EntityWrapper<Storehouse> inEw = new EntityWrapper<>();
            inEw.in("code", inHouseCodeList);
            List<Storehouse> outStorehouseList = storehouseService.selectList(outEw);
            List<Storehouse> inStorehouseList = storehouseService.selectList(inEw);

            //创建出库通知单
            for (Storehouse storehouse : outStorehouseList) {
                List<OtmOrderRelease> otmOrderReleaseList = listOutboundRelease(storehouse,
                        otmShipment.getOtmOrderReleaseList());
                insertOutboundNotice(otmShipment, otmOrderReleaseList);
            }

            //创建入库通知单
            for (Storehouse storehouse : inStorehouseList) {
                List<OtmOrderRelease> otmOrderReleaseList = listInboundRelease(storehouse,
                        otmShipment.getOtmOrderReleaseList());
                insertInboundNotice(otmShipment, otmOrderReleaseList);
            }
        }
    }

    /**
     * 根据仓库编码得到需出库的运单
     */
    private List<OtmOrderRelease> listOutboundRelease(Storehouse storehouse, List<OtmOrderRelease> otmOrderReleaseList) {
        List<OtmOrderRelease> outBoundReleaseList = new ArrayList<>();
        for (OtmOrderRelease otmOrderRelease : otmOrderReleaseList) {
            if (otmOrderRelease.getOriginLocationGid().equals(storehouse.getCode())) {
                otmOrderRelease.setOutboundHouseId(storehouse.getId());
                outBoundReleaseList.add(otmOrderRelease);
            }
        }
        return outBoundReleaseList;
    }

    /**
     * 根据仓库编码得到需入库的运单
     */
    private List<OtmOrderRelease> listInboundRelease(Storehouse storehouse,
                                                     List<OtmOrderRelease> otmOrderReleaseList) {
        List<OtmOrderRelease> inBoundReleaseList = new ArrayList<>();
        for (OtmOrderRelease otmOrderRelease : otmOrderReleaseList) {
            if (otmOrderRelease.getDestLocationGid().equals(storehouse.getCode())) {
                otmOrderRelease.setInboundHouseId(storehouse.getId());
                inBoundReleaseList.add(otmOrderRelease);
            }
        }
        return inBoundReleaseList;
    }

    /**
     * 指令修改时处理
     * <p>
     * 说明:
     * 1.两种修改情况：
     * 1）换车：
     * 提车：取数据库中对应指令的提车任务，已减少的车辆做取消、增加的创建新任务。
     * 出入库：减少的且未出入库的数据做取消，已出入库的不做处理；增加的创建新的出入库通知单明细(更新原出入库通知单)。
     * 2）改目的地
     * 只牵扯到入库通知单调整：原目的库的入库通知单做取消，并生成新目的库的入库通知单
     * </p>
     */
    private void shipmentUpdate(OtmShipment shipment,
                                OtmShipment oldShipment,
                                HashMap<String, Long> logLineCache,
                                Long logHeadId) {
        List<OtmOrderRelease> releaseList = shipment.getOtmOrderReleaseList();
        //数据缓存对象
        ArrayList<InboundNoticeLine> insertInLines = Lists.newArrayList();
        ArrayList<InboundNoticeLine> updateInLines = Lists.newArrayList();
        ArrayList<OutboundNoticeLine> insertOutLines = Lists.newArrayList();
        ArrayList<OutboundNoticeLine> updateOutLines = Lists.newArrayList();
        HashMap<String, InboundNoticeHeader> headerInHolder = Maps.newHashMap();
        HashMap<String, OutboundNoticeHeader> headerOutHolder = Maps.newHashMap();


        HashMap<String, OtmOrderRelease> releaseHolder = Maps.newHashMap();
        HashMap<String, InboundNoticeLine> inLineHolder = Maps.newHashMap();
        HashMap<String, OutboundNoticeLine> outLineHolder = Maps.newHashMap();
        //提车任务
        // 查原来的orderRelease数据
        EntityWrapper<OtmOrderRelease> reEW = new EntityWrapper<>();
        reEW.eq("shipment_gid", shipment.getShipmentGid())
                .ne("status", TableStatusEnum.STATUS_50.getCode());
        List<OtmOrderRelease> oldRes = releaseService.selectList(reEW);
        ArrayList<String> oldLineKeys = Lists.newArrayList();
        for (OtmOrderRelease oldRe : oldRes) {
            releaseHolder.put(oldRe.getReleaseGid(), oldRe);
            oldLineKeys.add(oldRe.getReleaseGid());
        }
        //通知单判断 先查询之前的通知单头/明细数据
        //判断头是否存在  -- 循环外查询避免重复查询
        EntityWrapper<InboundNoticeHeader> inHeadEW = new EntityWrapper<>();
        inHeadEW.eq("source_key", shipment.getShipmentGid())
                .notIn("status", TableStatusEnum.STATUS_50.getCode())
                .orderBy("gmt_create", false)
                .orderBy("id", false);
        List<InboundNoticeHeader> oldInHeaders = inboundNoticeHeaderService.selectList(inHeadEW);
        if (CollectionUtils.isNotEmpty(oldInHeaders)) {
            for (InboundNoticeHeader inHeader : oldInHeaders) {
                headerInHolder.put(inHeader.getSourceKey(), inHeader);
            }
        }
        //明细
        EntityWrapper<InboundNoticeLine> inLineEW = new EntityWrapper<>();
        inLineEW.in("line_source_key", oldLineKeys)
                .ne("status", TableStatusEnum.STATUS_50.getCode())
                .orderBy("gmt_create", false)
                .orderBy("id", false);
        List<InboundNoticeLine> inboundNoticeLines = inboundNoticeLineService.selectList(inLineEW);
        if (CollectionUtils.isNotEmpty(inboundNoticeLines)) {
            //用来缓存避免重复查询
            for (InboundNoticeLine oldLine : inboundNoticeLines) {
                inLineHolder.put(oldLine.getLineSourceKey(), oldLine);
            }
        }
        //判断头 -- 循环外查询避免重复查询
        EntityWrapper<OutboundNoticeHeader> outHeadEW = new EntityWrapper<>();
        outHeadEW.eq("source_key", shipment.getShipmentGid())
                .ne("status", TableStatusEnum.STATUS_50.getCode())
                .orderBy("gmt_create", false)
                .orderBy("id", false);
        List<OutboundNoticeHeader> oldOutHeaders = outboundNoticeHeaderService.selectList(outHeadEW);
        if (CollectionUtils.isNotEmpty(oldOutHeaders)) {
            for (OutboundNoticeHeader outHeader : oldOutHeaders) {
                headerOutHolder.put(outHeader.getSourceKey(), outHeader);
            }
        }

        //明细
        EntityWrapper<OutboundNoticeLine> outLineEW = new EntityWrapper<>();
        outLineEW.in("line_source_key", oldLineKeys)
                .ne("status", TableStatusEnum.STATUS_50.getCode())
                .orderBy("gmt_create", false)
                .orderBy("id", false);
        List<OutboundNoticeLine> outboundNoticeLines = outboundNoticeLineService.selectList(outLineEW);
        //用来缓存避免重复查询
        if (CollectionUtils.isNotEmpty(outboundNoticeLines)) {
            for (OutboundNoticeLine oldLine : outboundNoticeLines) {
                outLineHolder.put(oldLine.getLineSourceKey(), oldLine);
            }
        }
        //更新shipment
        if (!oldShipment.equals(shipment)) {
            shipment.setId(oldShipment.getId());
            shipment.setStatus(oldShipment.getStatus());
            shipment.setGmtCreate(oldShipment.getGmtCreate());
            shipment.setRemarks("指令更新");
            BeanUtils.copyProperties(shipment, oldShipment);
            otmShipmentService.updateById(oldShipment);
        }
        for (OtmOrderRelease newRe : releaseList) {
            OtmOrderRelease oldRelease = releaseHolder.get(newRe.getReleaseGid());
            if (Objects.isNull(oldRelease)) {
                //创建release明细
                releaseService.insert(newRe);
                //新增加的车 -- 创建任务
                Wrapper<OpDeliveryPoint> ew = new EntityWrapper<>();
                ew.eq("code", newRe.getOriginLocationGid());
                OpDeliveryPoint deliveryPoint = deliveryPointService.selectOne(ew);
                buildTask(shipment, newRe, deliveryPoint);
                //新增加的车 -- 创建通知单
                if (TableStatusEnum.STATUS_10.getCode().equals(shipment.getBoundType())) {
                    buildNewInNotice(shipment,
                            logLineCache,
                            logHeadId,
                            insertInLines,
                            inLineHolder,
                            newRe, headerInHolder);
                } else if (TableStatusEnum.STATUS_20.getCode().equals(shipment.getBoundType())) {
                    buildNewOutNotice(shipment,
                            logLineCache,
                            logHeadId,
                            insertOutLines,
                            outLineHolder,
                            newRe, headerOutHolder);
                } else if (TableStatusEnum.STATUS_30.getCode().equals(shipment.getBoundType())) {
                    buildNewInNotice(shipment,
                            logLineCache,
                            logHeadId,
                            insertInLines,
                            inLineHolder,
                            newRe, headerInHolder);
                    buildNewOutNotice(shipment,
                            logLineCache,
                            logHeadId,
                            insertOutLines,
                            outLineHolder,
                            newRe, headerOutHolder);
                }
            } else {
                //未改变
                if (oldRelease.equals(newRe)) {
                    //未改目的地 - 任务不用变动 通知单不用变动
                    // 把缓存下通知明细排除(后续剩下的数据就是要删掉的车)
                    InboundNoticeLine oldInLine = inLineHolder.get(oldRelease.getReleaseGid());
                    OutboundNoticeLine oldOutLine = outLineHolder.get(oldRelease.getReleaseGid());
                    if (TableStatusEnum.STATUS_10.getCode().equals(shipment.getBoundType())) {
                        //增加 原来存在release运单,但是对应没有生成通知单信息判断
                        if (Objects.isNull(oldInLine)) {
                            buildNewInNotice(shipment,
                                    logLineCache,
                                    logHeadId,
                                    insertInLines,
                                    inLineHolder,
                                    newRe, headerInHolder);
                        }
                        inLineHolder.remove(oldRelease.getReleaseGid());
                    } else if (TableStatusEnum.STATUS_20.getCode().equals(shipment.getBoundType())) {
                        if (Objects.isNull(oldOutLine)) {
                            buildNewOutNotice(shipment,
                                    logLineCache,
                                    logHeadId,
                                    insertOutLines,
                                    outLineHolder,
                                    newRe, headerOutHolder);
                        }
                        outLineHolder.remove(oldRelease.getReleaseGid());
                    } else if (TableStatusEnum.STATUS_30.getCode().equals(shipment.getBoundType())) {
                        if (Objects.isNull(oldInLine)) {
                            buildNewInNotice(shipment,
                                    logLineCache,
                                    logHeadId,
                                    insertInLines,
                                    inLineHolder,
                                    newRe, headerInHolder);
                        }
                        if (Objects.isNull(oldOutLine)) {
                            buildNewOutNotice(shipment,
                                    logLineCache,
                                    logHeadId,
                                    insertOutLines,
                                    outLineHolder,
                                    newRe, headerOutHolder);
                        }
                        inLineHolder.remove(oldRelease.getReleaseGid());
                        outLineHolder.remove(oldRelease.getReleaseGid());
                    }
                    //释放一致缓存
                    releaseHolder.remove(newRe.getReleaseGid());
                } else {
                    //更改字段
                    //更新shipment 只修改目的地为最新
                    OtmShipment otmShipment = new OtmShipment();
                    BeanUtils.copyProperties(shipment, otmShipment);
                    otmShipment.setId(oldShipment.getId());
                    otmShipmentService.updateById(otmShipment);
                    //更新release
                    OtmOrderRelease orderRelease = new OtmOrderRelease();
                    BeanUtils.copyProperties(newRe, orderRelease);
                    orderRelease.setId(oldRelease.getId());
                    releaseService.updateById(orderRelease);
                    //针对入库通知单处理生成新的入库通知单
                    if (TableStatusEnum.STATUS_10.getCode().equals(shipment.getBoundType())) {
                        fullyBuildNewIn(shipment,
                                logLineCache,
                                logHeadId,
                                insertInLines,
                                newRe,
                                headerInHolder);
                    }
                    if (TableStatusEnum.STATUS_20.getCode().equals(shipment.getBoundType())) {
                        fullyBuildNewOut(shipment,
                                logLineCache,
                                logHeadId,
                                insertOutLines,
                                newRe,
                                headerOutHolder);
                    }

                    if (TableStatusEnum.STATUS_30.getCode().equals(shipment.getBoundType())) {
                        fullyBuildNewIn(shipment,
                                logLineCache,
                                logHeadId,
                                insertInLines,
                                newRe,
                                headerInHolder);
                        fullyBuildNewOut(shipment,
                                logLineCache,
                                logHeadId,
                                insertOutLines,
                                newRe,
                                headerOutHolder);
                    }

                    //从缓存释放release
                    releaseHolder.remove(newRe.getReleaseGid());
                }
            }
        }

        //插入新增加的通知单数据
        if (CollectionUtils.isNotEmpty(insertInLines)) {
            inboundNoticeLineService.insertBatch(insertInLines);
        }
        if (CollectionUtils.isNotEmpty(insertOutLines)) {
            outboundNoticeLineService.insertBatch(insertOutLines);
        }
        //插入更换目的地后的新增的头
        if (!Objects.isNull(headerInHolder.get("insertHead"))) {
            inboundNoticeHeaderService.insert(headerInHolder.get("insertHead"));
        }
        if (!Objects.isNull(headerOutHolder.get("insertHead"))) {
            outboundNoticeHeaderService.insert(headerOutHolder.get("insertHead"));
        }
        //取消releaseHolder对应的运单数据  及提车任务数据(holder剩下的都是要取消的)
        deleteOldRelease(releaseHolder);
        //取消删除的老的入库通知单 -- holder 剩余的数据统一取消
        deleteOldInNotice(shipment, insertInLines, updateInLines, headerInHolder, inLineHolder);
        //出库通知单  --保持头的linecount 和 状态随时更新
        deleteOldOutNotice(shipment, insertOutLines, updateOutLines, headerOutHolder, outLineHolder);
        //更新头holder到最新状态
        if (!Objects.isNull(headerInHolder.get(shipment.getShipmentGid()))) {
            InboundNoticeHeader header = headerInHolder.get(shipment.getShipmentGid());
            header.setGmtModified(null);
            inboundNoticeHeaderService.insertOrUpdate(header);
        }
        if (!Objects.isNull(headerOutHolder.get(shipment.getShipmentGid()))) {
            OutboundNoticeHeader header = headerOutHolder.get(shipment.getShipmentGid());
            header.setGmtModified(null);
            outboundNoticeHeaderService.insertOrUpdate(header);
        }
    }

    private void deleteOldRelease(HashMap<String, OtmOrderRelease> releaseHolder) {
        if (!releaseHolder.isEmpty()) {
            Set<Map.Entry<String, OtmOrderRelease>> entries = releaseHolder.entrySet();
            for (Map.Entry<String, OtmOrderRelease> entry : entries) {
                OtmOrderRelease oldRe = entry.getValue();
                OtmOrderRelease orderRelease = new OtmOrderRelease();
                orderRelease.setId(oldRe.getId());
                orderRelease.setStatus(TableStatusEnum.STATUS_50.getCode());
                orderRelease.setRemarks("指令删除数据");
                releaseService.updateById(orderRelease);
                //取消提车任务
                EntityWrapper<OpTask> taskEW = new EntityWrapper<>();
                taskEW.eq("waybill_no", oldRe.getReleaseGid())
                        .notIn("status", TableStatusEnum.STATUS_50.getCode());
                OpTask task = new OpTask();
                task.setStatus(TableStatusEnum.STATUS_50.getCode());
                taskService.update(task, taskEW);
            }
        }
    }

    private void deleteOldOutNotice(OtmShipment shipment, ArrayList<OutboundNoticeLine> insertOutLines, ArrayList<OutboundNoticeLine> updateOutLines, HashMap<String, OutboundNoticeHeader> headerOutHolder, HashMap<String, OutboundNoticeLine> outLineHolder) {
        if (!outLineHolder.isEmpty()) {
            Set<Map.Entry<String, OutboundNoticeLine>> entries = outLineHolder.entrySet();
            for (Map.Entry<String, OutboundNoticeLine> entry : entries) {
                OutboundNoticeLine oldLine = entry.getValue();
                OutboundNoticeLine noticeLine = new OutboundNoticeLine();
                noticeLine.setId(oldLine.getId());
                noticeLine.setStatus(TableStatusEnum.STATUS_50.getCode());
                noticeLine.setRemarks("指令删除数据");
                updateOutLines.add(noticeLine);
                outboundNoticeLineService.updateById(noticeLine);
                //fix 2019-01-15 查询备料 如果备料明细状态未完成->取消对应备料 已完成->不处理
                OutboundPrepareLine line = new OutboundPrepareLine();
                line.setStatus(TableStatusEnum.STATUS_40.getCode());
                line.setGmtModified(null);
                line.setRemarks("指令取消未完成备料");

                EntityWrapper<OutboundPrepareLine> plEW = new EntityWrapper<>();
                plEW.eq("notice_line_id", oldLine.getId())
                        .in("status", "10,20");
                prepareLineService.update(line, plEW);

                //fix 2019-01-15  更新钥匙的明细状态
                OutboundKeyPrepareLine keyPrepareLine = new OutboundKeyPrepareLine();
                keyPrepareLine.setStatus(TableStatusEnum.STATUS_50.getCode());
                keyPrepareLine.setRemarks("指令取消未完成备料");
                keyPrepareLine.setGmtModified(null);
                EntityWrapper<OutboundKeyPrepareLine> kplEW = new EntityWrapper<>();
                kplEW.eq("notice_line_id", oldLine.getId())
                        .in("status", "10,20");
                keyPrepareLineService.update(keyPrepareLine, kplEW);

            }
            if (CollectionUtils.isNotEmpty(updateOutLines)) {
                OutboundNoticeHeader noticeHeader = headerOutHolder.get(shipment.getShipmentGid());
                OutboundNoticeHeader header = new OutboundNoticeHeader();
                header.setId(noticeHeader.getId());
                header.setLineCount(noticeHeader.getLineCount() - updateOutLines.size());
                header.setExpectSumQty(noticeHeader.getExpectSumQty()
                        .subtract(BigDecimal.valueOf(updateOutLines.size())));
                if (0 == header.getLineCount()) {
                    //全部取消
                    header.setStatus(TableStatusEnum.STATUS_50.getCode());
                } else {
                    //部分出库-->全部出库
                    if (CollectionUtils.isEmpty(insertOutLines)) {
                        //
                        EntityWrapper<OutboundNoticeLine> lineEW = new EntityWrapper<>();
                        lineEW.eq("header_id", noticeHeader)
                                .eq("status", TableStatusEnum.STATUS_30.getCode());
                        int count = outboundNoticeLineService.selectCount(lineEW);
                        if (header.getLineCount() == count) {
                            header.setStatus(TableStatusEnum.STATUS_30.getCode());
                        }
                    }
                }
                headerOutHolder.put(shipment.getShipmentGid(), header);
            }
        }
    }

    private void deleteOldInNotice(OtmShipment shipment, ArrayList<InboundNoticeLine> insertInLines, ArrayList<InboundNoticeLine> updateInLines, HashMap<String, InboundNoticeHeader> headerInHolder, HashMap<String, InboundNoticeLine> inLineHolder) {
        if (!inLineHolder.isEmpty()) {
            Set<Map.Entry<String, InboundNoticeLine>> entries = inLineHolder.entrySet();
            for (Map.Entry<String, InboundNoticeLine> entry : entries) {
                InboundNoticeLine oldLine = entry.getValue();
                InboundNoticeLine noticeLine = new InboundNoticeLine();
                noticeLine.setId(oldLine.getId());
                noticeLine.setStatus(TableStatusEnum.STATUS_50.getCode());
                noticeLine.setRemarks("指令删除数据");
                updateInLines.add(noticeLine);
                inboundNoticeLineService.updateById(noticeLine);
            }
            if (CollectionUtils.isNotEmpty(updateInLines)) {
                InboundNoticeHeader noticeHeader = headerInHolder.get(shipment.getShipmentGid());
                noticeHeader.setLineCount(noticeHeader.getLineCount() - updateInLines.size());
                noticeHeader.setExpectSumQty(noticeHeader.getExpectSumQty()
                        .subtract(BigDecimal.valueOf(updateInLines.size())));
                if (0 == noticeHeader.getLineCount()) {
                    //全部取消
                    noticeHeader.setStatus(TableStatusEnum.STATUS_50.getCode());
                } else {
                    //部分出库-->全部出库
                    if (CollectionUtils.isEmpty(insertInLines)) {
                        EntityWrapper<InboundNoticeLine> lineEW = new EntityWrapper<>();
                        lineEW.eq("header_id", noticeHeader)
                                .eq("status", TableStatusEnum.STATUS_30.getCode());
                        int count = inboundNoticeLineService.selectCount(lineEW);
                        if (noticeHeader.getLineCount() == count) {
                            noticeHeader.setStatus(TableStatusEnum.STATUS_30.getCode());
                        }
                    }
                }
                headerInHolder.put(shipment.getShipmentGid(), noticeHeader);
            }
        }
    }

    private void fullyBuildNewIn(OtmShipment shipment,
                                 HashMap<String, Long> logLineCache,
                                 Long logHeadId,
                                 ArrayList<InboundNoticeLine> insertInLines,
                                 OtmOrderRelease newRe,
                                 HashMap<String, InboundNoticeHeader> headerInHolder) {
        InboundNoticeHeader oldHeader = headerInHolder.get(shipment.getShipmentGid());
        if (!Objects.isNull(oldHeader)) {
            InboundNoticeHeader noticeHeader = new InboundNoticeHeader();
            BeanUtils.copyProperties(oldHeader, noticeHeader);
            noticeHeader.setId(oldHeader.getId());
            noticeHeader.setRemarks("换目的地修改删除");
            noticeHeader.setStatus(TableStatusEnum.STATUS_50.getCode());
            headerInHolder.put(shipment.getShipmentGid(), noticeHeader);
        }
        //插入新的头
        InboundNoticeHeader noticeHeader;
        if (Objects.isNull(headerInHolder.get("insertHead"))) {
            noticeHeader = buildInHead(shipment, logHeadId, newRe);
            headerInHolder.put("insertHead", noticeHeader);
        } else {
            noticeHeader = headerInHolder.get("insertHead");
        }
        //以前没明细入库通知数据  直接new head  / 明细
        InboundNoticeLine newInLine = buildNewInLine(logLineCache, newRe, noticeHeader);
        insertInLines.add(newInLine);
        noticeHeader.setLineCount(noticeHeader.getLineCount() + 1);
        noticeHeader.setExpectSumQty(noticeHeader.getExpectSumQty().add(BigDecimal.ONE));
        noticeHeader.addInboundNoticeLine(newInLine);
        headerInHolder.put("insertHead", noticeHeader);
    }

    private void fullyBuildNewOut(OtmShipment shipment,
                                  HashMap<String, Long> logLineCache,
                                  Long logHeadId,
                                  ArrayList<OutboundNoticeLine> insertOutLines,
                                  OtmOrderRelease newRe,
                                  HashMap<String, OutboundNoticeHeader> headerOutHolder) {
        OutboundNoticeHeader oldHeader = headerOutHolder.get(shipment.getShipmentGid());
        if (!Objects.isNull(oldHeader)) {
            OutboundNoticeHeader noticeHeader = new OutboundNoticeHeader();
            BeanUtils.copyProperties(oldHeader, noticeHeader);
            noticeHeader.setId(oldHeader.getId());
            noticeHeader.setRemarks("换目的地修改删除");
            noticeHeader.setStatus(TableStatusEnum.STATUS_50.getCode());
            headerOutHolder.put(shipment.getShipmentGid(), noticeHeader);
        }
        //插入新的头
        OutboundNoticeHeader noticeHeader;
        if (Objects.isNull(headerOutHolder.get("insertHead"))) {
            noticeHeader = buildOutHead(shipment, logHeadId, newRe);
            headerOutHolder.put("insertHead", noticeHeader);
        } else {
            noticeHeader = headerOutHolder.get("insertHead");
        }
        //以前没明细  直接new head  / 明细
        OutboundNoticeLine newOutLine = buildNewOutLine(logLineCache, newRe, noticeHeader);
        insertOutLines.add(newOutLine);
        noticeHeader.setLineCount(noticeHeader.getLineCount() + 1);
        noticeHeader.setExpectSumQty(noticeHeader.getExpectSumQty().add(BigDecimal.ONE));
        noticeHeader.addOutboundNoticeLine(newOutLine);
        headerOutHolder.put("insertHead", noticeHeader);
    }


    private void buildNewOutNotice(OtmShipment shipment,
                                   HashMap<String, Long> logLineCache,
                                   Long logHeadId,
                                   ArrayList<OutboundNoticeLine> insertOutLines,
                                   HashMap<String, OutboundNoticeLine> outLineHolder,
                                   OtmOrderRelease newRe,
                                   HashMap<String, OutboundNoticeHeader> headerOutHolder) {
        OutboundNoticeHeader outboundNoticeHeader;
        if (headerOutHolder.isEmpty() && Objects.isNull(headerOutHolder.get(shipment.getShipmentGid()))) {
            outboundNoticeHeader = buildOutHead(shipment, logHeadId, newRe);
            //保存头到缓存
            headerOutHolder.put(shipment.getShipmentGid(), outboundNoticeHeader);
        } else {
            outboundNoticeHeader = headerOutHolder.get(shipment.getShipmentGid());
        }
        OutboundNoticeLine oldLine = outLineHolder.get(newRe.getReleaseGid());
        if (Objects.isNull(oldLine)) {
            //生成对应明细
            OutboundNoticeLine newOutLine = buildNewOutLine(logLineCache, newRe, outboundNoticeHeader);
            outboundNoticeHeader.addOutboundNoticeLine(newOutLine);
            insertOutLines.add(newOutLine);
            //头处理
            //头是全部出库-->部分出库
            if (TableStatusEnum.STATUS_30.getCode().equals(outboundNoticeHeader.getStatus())) {
                outboundNoticeHeader.setStatus(TableStatusEnum.STATUS_20.getCode());
            }
            outboundNoticeHeader.setLineCount(outboundNoticeHeader.getLineCount() + 1);
            outboundNoticeHeader.setExpectSumQty(outboundNoticeHeader.getExpectSumQty().add(BigDecimal.ONE));
            outboundNoticeHeader.addOutboundNoticeLine(newOutLine);
            headerOutHolder.put(shipment.getShipmentGid(), outboundNoticeHeader);
        }
    }

    private void buildNewInNotice(OtmShipment shipment,
                                  HashMap<String, Long> logLineCache,
                                  Long logHeadId,
                                  ArrayList<InboundNoticeLine> insertInLines,
                                  HashMap<String, InboundNoticeLine> inLineHolder,
                                  OtmOrderRelease newRe,
                                  HashMap<String, InboundNoticeHeader> headerInHolder) {
        InboundNoticeHeader inboundNoticeHeader = getHeader(shipment, logHeadId, newRe, headerInHolder);
        InboundNoticeLine oldLine = inLineHolder.get(newRe.getReleaseGid());
        if (Objects.isNull(oldLine)) {
            //以前没明细入库通知数据  直接new head  / 明细
            InboundNoticeLine newInLine = buildNewInLine(logLineCache, newRe, inboundNoticeHeader);
            insertInLines.add(newInLine);
            //设置头
            if (TableStatusEnum.STATUS_30.getCode().equals(inboundNoticeHeader.getStatus())) {
                inboundNoticeHeader.setStatus(TableStatusEnum.STATUS_20.getCode());
            }
            inboundNoticeHeader.setExpectSumQty(inboundNoticeHeader.getExpectSumQty().add(BigDecimal.ONE));
            inboundNoticeHeader.setLineCount(inboundNoticeHeader.getLineCount() + 1);
            inboundNoticeHeader.addInboundNoticeLine(newInLine);
            headerInHolder.put(shipment.getShipmentGid(), inboundNoticeHeader);
        }
    }

    private InboundNoticeHeader getHeader(OtmShipment shipment,
                                          Long logHeadId,
                                          OtmOrderRelease newRe,
                                          HashMap<String, InboundNoticeHeader> headerInHolder) {
        InboundNoticeHeader inboundNoticeHeader;
        if (headerInHolder.isEmpty() && Objects.isNull(headerInHolder.get(shipment.getShipmentGid()))) {
            inboundNoticeHeader = buildInHead(shipment, logHeadId, newRe);
            //保存头到缓存
            headerInHolder.put(shipment.getShipmentGid(), inboundNoticeHeader);
        } else {
            inboundNoticeHeader = headerInHolder.get(shipment.getShipmentGid());
        }
        return inboundNoticeHeader;
    }

    private OutboundNoticeLine buildNewOutLine(HashMap<String, Long> logLineCache,
                                               OtmOrderRelease newRe,
                                               OutboundNoticeHeader onh) {
        OutboundNoticeLine newLine = new OutboundNoticeLine();
        newLine.setId(snowFlakeId.nextId());
        newLine.setHeaderId(onh.getId());
        //newLine.setSeq("");
        newLine.setOwnerId(newRe.getCustomerId());
        newLine.setOwnerOrderNo(newRe.getCusOrderNo()); //调整存储客户运单号
        newLine.setLogLineId(logLineCache.get(newRe.getReleaseGid()));
        newLine.setLineSourceKey(newRe.getReleaseGid());
        newLine.setLineSourceNo(newRe.getReleaseGid());
        newLine.setMaterielId(newRe.getStanVehicleType());
        //newLine.setMaterielCode("");
        //newLine.setMaterielName("");
        newLine.setUom(onh.getUom());
        newLine.setExpectQty(BigDecimal.ONE);
        newLine.setOutboundQty(BigDecimal.ZERO);
        newLine.setLotNo1(newRe.getVin());
        newLine.setStatus(TableStatusEnum.STATUS_10.getCode());
        newLine.setRemarks("指令修改新增");
        newLine.setGmtCreate(null);
        newLine.setGmtModified(null);
        return newLine;
    }

    private InboundNoticeLine buildNewInLine(HashMap<String, Long> logLineCache,
                                             OtmOrderRelease newRe,
                                             InboundNoticeHeader inh) {
        InboundNoticeLine newInLine = new InboundNoticeLine();
        newInLine.setId(snowFlakeId.nextId());
        newInLine.setHeaderId(inh.getId());
        //newInLine.setSeq("");
        newInLine.setOwnerId(newRe.getCustomerId());
        newInLine.setOwnerOrderNo(newRe.getCusOrderNo()); // 调整存储客户运单号
        newInLine.setLogLineId(logLineCache.get(newRe.getReleaseGid()));
        newInLine.setLineSourceKey(newRe.getReleaseGid());
        newInLine.setLineSourceNo(newRe.getReleaseGid());
        newInLine.setMaterielId(newRe.getStanVehicleType());
        //newInLine.setMaterielCode("");
        //newInLine.setMaterielName("");
        newInLine.setUom(inh.getUom());
        newInLine.setExpectQty(BigDecimal.ONE);
        newInLine.setInboundQty(BigDecimal.ZERO);
        newInLine.setLotNo1(newRe.getVin());
        newInLine.setStatus(TableStatusEnum.STATUS_10.getCode());
        newInLine.setRemarks("指令修改新增");
        newInLine.setGmtCreate(null);
        newInLine.setGmtModified(null);
        return newInLine;
    }

    private OutboundNoticeHeader buildOutHead(OtmShipment shipment, Long logHeadId, OtmOrderRelease newRe) {
        OutboundNoticeHeader onh = new OutboundNoticeHeader();
        onh.setId(snowFlakeId.nextId());
        onh.setStoreHouseId(newRe.getOutboundHouseId());
        onh.setNoticeNo(businessDocNumberService.getOutboundNoticeNo());
        onh.setOwnerId(newRe.getCustomerId());
        onh.setOwnerOrderNo(newRe.getCusOrderNo());
        onh.setOrderDate(new Date());
        onh.setCarrierId(shipment.getServiceProviderGid());
        onh.setCarrierName(shipment.getServiceProviderName());
        onh.setTransportMethod(shipment.getTransportModeGid());
        onh.setPlateNumber(shipment.getPlateNo());
        onh.setDriverName(shipment.getDriverName());
        onh.setDriverPhone(shipment.getDriverPhone());
        onh.setExpectShipDateLower(shipment.getExpcetShipDate());
        onh.setUom(MeasureUnit.TAI);
        onh.setExpectSumQty(BigDecimal.ZERO);
        onh.setOutboundSumQty(BigDecimal.ZERO);
        onh.setLineCount(0);
        onh.setLogHeaderId(logHeadId);
        onh.setSourceKey(shipment.getShipmentGid());
        onh.setSourceNo(shipment.getShipmentGid());
        onh.setStatus(TableStatusEnum.STATUS_10.getCode());
        onh.setRemarks("指令修改新增");
        onh.setUserCreate("OTM");
        onh.setUserModified("OTM");
        onh.setGmtCreate(null);
        onh.setGmtModified(null);
        return onh;
    }

    private InboundNoticeHeader buildInHead(OtmShipment shipment, Long logHeadId, OtmOrderRelease newRe) {
        InboundNoticeHeader inh = new InboundNoticeHeader();
        inh.setId(snowFlakeId.nextId());
        inh.setStoreHouseId(newRe.getInboundHouseId());
        inh.setNoticeNo(businessDocNumberService.getInboundNoticeNo());
        inh.setOwnerId(newRe.getCustomerId());
        inh.setOwnerOrderNo(newRe.getCusOrderNo());
        inh.setOrderDate(new Date());
        inh.setCarrierId(shipment.getServiceProviderGid());
        inh.setCarrierName(shipment.getServiceProviderName());
        inh.setTransportMethod(shipment.getTransportModeGid());
        inh.setPlateNumber(shipment.getPlateNo());
        inh.setDriverName(shipment.getDriverName());
        inh.setDriverPhone(shipment.getDriverPhone());
        inh.setExpectRecvDateLower(shipment.getExpectArriveDate());
        inh.setUom(MeasureUnit.TAI);
        inh.setExpectSumQty(BigDecimal.ZERO);
        inh.setInboundSumQty(BigDecimal.ZERO);
        inh.setLineCount(0);
        inh.setLogHeaderId(logHeadId);
        inh.setSourceKey(shipment.getShipmentGid());
        inh.setSourceNo(shipment.getShipmentGid());
        inh.setStatus(TableStatusEnum.STATUS_10.getCode());
        inh.setRemarks("指令修改新增");
        inh.setUserCreate("OTM");
        inh.setUserModified("OTM");
        inh.setGmtCreate(null);
        inh.setGmtModified(null);
        return inh;
    }

    private void buildTask(OtmShipment shipment, OtmOrderRelease newRe, OpDeliveryPoint deliveryPoint) {
        if (!Objects.isNull(deliveryPoint)) {
            OpTask opTask = new OpTask();
            opTask.setDispatchNo(shipment.getShipmentGid());
            opTask.setWaybillNo(newRe.getReleaseGid());
            opTask.setStatus(Task.Status.CREATED);
            if (deliveryPoint.getIsSeek().equals(YesOrNo.YES)) {
                opTask.setType(Task.Type.SEEK);
                opTask.setId(String.valueOf(snowFlakeId.nextId()));
                taskService.insert(opTask);
            }
            if (deliveryPoint.getIsMove().equals(YesOrNo.YES)) {
                opTask.setType(Task.Type.MOVE);
                opTask.setId(String.valueOf(snowFlakeId.nextId()));
                taskService.insert(opTask);
            }
            if (deliveryPoint.getIsPick().equals(YesOrNo.YES)) {
                opTask.setType(Task.Type.PICK);
                opTask.setId(String.valueOf(snowFlakeId.nextId()));
                taskService.insert(opTask);
            }
        }
    }


    /**
     * 指令删除时处理
     * <p>
     * 取消相关的提车任务、指令、任务，未入库的入库通知单做取消、未出库的出库通知单做取消
     * </p>
     */
    private void shipmentDelete(OtmShipment newShipment,
                                OtmShipment oldShipment) {
        //修改状态
        EntityWrapper<OtmOrderRelease> oldReEW = new EntityWrapper<>();
        oldReEW.eq("shipment_gid", newShipment.getShipmentGid())
                .ne("status", TableStatusEnum.STATUS_50.getCode());
        List<OtmOrderRelease> otmOrderReleases = releaseService.selectList(oldReEW);
        OtmShipment shipment = new OtmShipment();
        shipment.setStatus(TableStatusEnum.STATUS_50.getCode());
        shipment.setTransactionCode("RC");
        EntityWrapper<OtmShipment> shipEW = new EntityWrapper<>();
        shipEW.eq("shipment_gid", newShipment.getShipmentGid());
        otmShipmentService.update(shipment, shipEW);
        for (OtmOrderRelease orderRelease : otmOrderReleases) {
            OtmOrderRelease release = new OtmOrderRelease();
            release.setRemarks("指令删除");
            release.setStatus(TableStatusEnum.STATUS_50.getCode());
            EntityWrapper<OtmOrderRelease> releaseEW = new EntityWrapper<>();
            releaseEW.eq("release_gid", orderRelease.getReleaseGid())
                    .eq("shipment_gid", orderRelease.getShipmentGid());
            releaseService.update(release, releaseEW);
            //任务单据的状态
            EntityWrapper<OpTask> taskEW = new EntityWrapper<>();
            taskEW.eq("waybill_no", orderRelease.getReleaseGid())
                    .notIn("status", TableStatusEnum.STATUS_50.getCode());
            OpTask task = new OpTask();
            task.setStatus(TableStatusEnum.STATUS_50.getCode());
            taskService.update(task, taskEW);
            //通知单状态
            if (TableStatusEnum.STATUS_10.getCode().equals(oldShipment.getBoundType())) {
                //未入库
                deleteInboundNotice(orderRelease);
            } else if (TableStatusEnum.STATUS_20.getCode().equals(oldShipment.getBoundType())) {
                //未出库
                deleteOutboundNotice(orderRelease);
            } else if (TableStatusEnum.STATUS_30.getCode().equals(oldShipment.getBoundType())) {
                deleteInboundNotice(orderRelease);
                deleteOutboundNotice(orderRelease);
            }
        }
    }

    private void deleteOutboundNotice(OtmOrderRelease orderRelease) {
        EntityWrapper<OutboundNoticeLine> outEW = new EntityWrapper<>();
        outEW.eq("line_source_key", orderRelease.getReleaseGid())
                .eq("status", TableStatusEnum.STATUS_10.getCode())
                .orderBy("gmt_create", false)
                .orderBy("id", false);
        OutboundNoticeLine noticeLine = outboundNoticeLineService.selectOne(outEW);
        if (!Objects.isNull(noticeLine)) {
            OutboundNoticeHeader noticeHeader = outboundNoticeHeaderService.selectById(noticeLine.getHeaderId());
            if (TableStatusEnum.STATUS_10.getCode().equals(noticeHeader.getStatus())) {
                OutboundNoticeHeader header = new OutboundNoticeHeader();
                header.setStatus(TableStatusEnum.STATUS_50.getCode());
                header.setId(noticeHeader.getId());
                outboundNoticeHeaderService.updateById(header);
            }
            OutboundNoticeLine outboundNoticeLine = new OutboundNoticeLine();
            outboundNoticeLine.setId(noticeLine.getId());
            outboundNoticeLine.setStatus(TableStatusEnum.STATUS_50.getCode());
            outboundNoticeLine.setRemarks("指令删除");
            outboundNoticeLineService.updateById(outboundNoticeLine);
        }
    }

    private void deleteInboundNotice(OtmOrderRelease orderRelease) {
        EntityWrapper<InboundNoticeLine> inEW = new EntityWrapper<>();
        inEW.eq("line_source_key", orderRelease.getReleaseGid())
                .eq("status", TableStatusEnum.STATUS_10.getCode())
                .orderBy("gmt_create", false)
                .orderBy("id", false);
        InboundNoticeLine noticeLine = inboundNoticeLineService.selectOne(inEW);
        if (!Objects.isNull(noticeLine)) {
            InboundNoticeHeader noticeHeader = inboundNoticeHeaderService.selectById(noticeLine.getHeaderId());
            if (TableStatusEnum.STATUS_10.getCode().equals(noticeHeader.getStatus())) {
                InboundNoticeHeader header = new InboundNoticeHeader();
                header.setStatus(TableStatusEnum.STATUS_50.getCode());
                header.setId(noticeHeader.getId());
                header.setRemarks("指令删除");
                inboundNoticeHeaderService.updateById(header);
            }
            InboundNoticeLine inboundNoticeLine = new InboundNoticeLine();
            inboundNoticeLine.setId(noticeLine.getId());
            inboundNoticeLine.setRemarks("指令删除");
            inboundNoticeLine.setStatus(TableStatusEnum.STATUS_50.getCode());
            inboundNoticeLineService.updateById(inboundNoticeLine);
        }
    }

    /**
     * 创建现场提车任务
     */
    private void buildOpTask(OtmShipment otmShipment) {
        for (OtmOrderRelease orderRelease : otmShipment.getOtmOrderReleaseList()) {
            Wrapper<OpDeliveryPoint> ew = new EntityWrapper<>();
            ew.eq("code", orderRelease.getOriginLocationGid());
            OpDeliveryPoint deliveryPoint = deliveryPointService.selectOne(ew);
            //构建对应的车辆任务信息
            buildTask(otmShipment, orderRelease, deliveryPoint);
        }
    }

    /**
     * 创建入库通知单
     */
    private void insertInboundNotice(OtmShipment otmShipment, List<OtmOrderRelease> otmOrderReleaseList) {

        if (Objects.isNull(otmOrderReleaseList) || otmOrderReleaseList.size() == 0) throw new BaseException("入库运单为空");

        InboundNoticeHeader inboundNoticeHeader = new InboundNoticeHeader();
        inboundNoticeHeader.setId(snowFlakeId.nextId());
        inboundNoticeHeader.setStoreHouseId(otmOrderReleaseList.get(0).getInboundHouseId());
        inboundNoticeHeader.setNoticeNo(businessDocNumberService.getInboundNoticeNo());
//        inboundNoticeHeader.setOwnerId();
        inboundNoticeHeader.setOwnerOrderNo(otmShipment.getShipmentGid());
        inboundNoticeHeader.setOrderDate(otmShipment.getExpectInboundDate());
        inboundNoticeHeader.setCarrierId(otmShipment.getServiceProviderGid());
        inboundNoticeHeader.setCarrierName(otmShipment.getServiceProviderName());
        inboundNoticeHeader.setTransportMethod(otmShipment.getTransportModeGid());
        inboundNoticeHeader.setPlateNumber(otmShipment.getPlateNo());
        inboundNoticeHeader.setDriverName(otmShipment.getDriverName());
        inboundNoticeHeader.setDriverPhone(otmShipment.getDriverPhone());
        inboundNoticeHeader.setExpectRecvDateLower(otmShipment.getExpectArriveDate());
//        inboundNoticeHeader.setExpectRecvDateUpper();
        inboundNoticeHeader.setUom(MeasureUnit.TAI);
        inboundNoticeHeader.setExpectSumQty(new BigDecimal(otmOrderReleaseList.size()));
        inboundNoticeHeader.setLineCount(otmOrderReleaseList.size());
        inboundNoticeHeader.setLogHeaderId(otmShipment.getLogHeaderId());
        inboundNoticeHeader.setSourceKey(otmShipment.getShipmentGid());
        inboundNoticeHeader.setSourceNo(otmShipment.getShipmentGid());
        inboundNoticeHeader.setRemarks("指令新增");
        inboundNoticeHeader.setInboundSumQty(BigDecimal.ZERO);
        inboundNoticeHeader.setUserCreate(SysSourceEnum.OTM_CREATE.getName());
        inboundNoticeHeader.setUserModified(SysSourceEnum.OTM_CREATE.getName());

        for (OtmOrderRelease otmOrderRelease : otmOrderReleaseList) {
            InboundNoticeLine inboundNoticeLine = new InboundNoticeLine();
            inboundNoticeLine.setId(snowFlakeId.nextId());
            inboundNoticeLine.setHeaderId(inboundNoticeHeader.getId());
//            inboundNoticeLine.setSeq();
            inboundNoticeLine.setOwnerId(otmOrderRelease.getCustomerId());
            inboundNoticeLine.setOwnerOrderNo(otmOrderRelease.getCusOrderNo());//调整存储客户运单号
            inboundNoticeLine.setLogLineId(otmOrderRelease.getLogLineId());
            inboundNoticeLine.setLineSourceKey(otmOrderRelease.getReleaseGid());
            inboundNoticeLine.setLineSourceNo(otmOrderRelease.getReleaseGid());
            inboundNoticeLine.setMaterielId(otmOrderRelease.getStanVehicleType());
//            inboundNoticeLine.setMaterielCode();
//            inboundNoticeLine.setMaterielName();
            inboundNoticeLine.setUom(inboundNoticeHeader.getUom());
            inboundNoticeLine.setExpectQty(BigDecimal.ONE);
            inboundNoticeLine.setInboundQty(BigDecimal.ZERO);
            //inboundNoticeLine.setLotNo0(otmOrderRelease.getReleaseGid());
            inboundNoticeLine.setLotNo1(otmOrderRelease.getVin());
            inboundNoticeLine.setStatus(Status.Inbound.NOT);
            inboundNoticeLine.setRemarks("指令新增");
            inboundNoticeHeader.addInboundNoticeLine(inboundNoticeLine);
        }
        inboundNoticeHeaderService.insertInboundNotice(inboundNoticeHeader);
    }

    /**
     * 创建出库通知单
     */
    private void insertOutboundNotice(OtmShipment otmShipment, List<OtmOrderRelease> otmOrderReleaseList) {
        if (Objects.isNull(otmOrderReleaseList) || otmOrderReleaseList.size() == 0) {
            throw new BaseException("入库运单为空");
        }
        OutboundNoticeHeader outboundNoticeHeader = new OutboundNoticeHeader();
        outboundNoticeHeader.setId(snowFlakeId.nextId());
        outboundNoticeHeader.setStoreHouseId(otmOrderReleaseList.get(0).getOutboundHouseId());
        outboundNoticeHeader.setNoticeNo(businessDocNumberService.getOutboundNoticeNo());
//        inboundNoticeHeader.setOwnerId();
        outboundNoticeHeader.setOwnerOrderNo(otmShipment.getShipmentGid());
        outboundNoticeHeader.setOrderDate(otmShipment.getExpectInboundDate());
        outboundNoticeHeader.setCarrierId(otmShipment.getServiceProviderGid());
        outboundNoticeHeader.setCarrierName(otmShipment.getServiceProviderName());
        outboundNoticeHeader.setTransportMethod(otmShipment.getTransportModeGid());
        outboundNoticeHeader.setPlateNumber(otmShipment.getPlateNo());
        outboundNoticeHeader.setDriverName(otmShipment.getDriverName());
        outboundNoticeHeader.setDriverPhone(otmShipment.getDriverPhone());
        outboundNoticeHeader.setExpectShipDateLower(otmShipment.getExpcetShipDate());
//        inboundNoticeHeader.setExpectRecvDateUpper();
        outboundNoticeHeader.setUom(MeasureUnit.TAI);
        outboundNoticeHeader.setExpectSumQty(new BigDecimal(otmOrderReleaseList.size()));
        outboundNoticeHeader.setLineCount(otmOrderReleaseList.size());
        outboundNoticeHeader.setLogHeaderId(otmShipment.getLogHeaderId());
        outboundNoticeHeader.setSourceKey(otmShipment.getShipmentGid());
        outboundNoticeHeader.setSourceNo(otmShipment.getShipmentGid());
        outboundNoticeHeader.setOutboundSumQty(BigDecimal.ZERO);
        outboundNoticeHeader.setStatus(TableStatusEnum.STATUS_10.getCode());

        for (OtmOrderRelease otmOrderRelease : otmOrderReleaseList) {
            OutboundNoticeLine outboundNoticeLine = new OutboundNoticeLine();
            outboundNoticeLine.setId(snowFlakeId.nextId());
            outboundNoticeLine.setHeaderId(outboundNoticeHeader.getId());
//            inboundNoticeLine.setSeq();
            outboundNoticeLine.setOwnerId(otmOrderRelease.getCustomerId());
            outboundNoticeLine.setOwnerOrderNo(otmOrderRelease.getCusOrderNo());
            outboundNoticeLine.setLogLineId(otmOrderRelease.getLogLineId());
            outboundNoticeLine.setLineSourceKey(otmOrderRelease.getReleaseGid());
            outboundNoticeLine.setLineSourceNo(otmOrderRelease.getReleaseGid());
            outboundNoticeLine.setMaterielId(otmOrderRelease.getStanVehicleType());
//            inboundNoticeLine.setMaterielCode();
//            inboundNoticeLine.setMaterielName();
            outboundNoticeLine.setUom(outboundNoticeHeader.getUom());
            outboundNoticeLine.setExpectQty(BigDecimal.ONE);
            outboundNoticeLine.setOutboundQty(BigDecimal.ZERO);
            //outboundNoticeLine.setLotNo0(otmOrderRelease.getReleaseGid());
            outboundNoticeLine.setLotNo1(otmOrderRelease.getVin());
            outboundNoticeLine.setStatus(Status.Inbound.NOT);
            outboundNoticeHeader.addOutboundNoticeLine(outboundNoticeLine);
        }
        outboundNoticeHeaderService.insertOutboundNotice(outboundNoticeHeader);
    }

    /**
     * 更新日志
     */
    private ItfImplogHeader updateLogByShipment(Long logHeaderId, OtmShipment otmShipment) {
        ItfImplogHeader itfImplogHeader = new ItfImplogHeader();
        itfImplogHeader.setId(logHeaderId);
//            itfImplogHeader.setOwnerId();
//            itfImplogHeader.setId();
//            itfImplogHeader.setOwnerId();
        itfImplogHeader.setOwnerOrderNo(otmShipment.getShipmentGid());//货主单号
        itfImplogHeader.setType(getOrderType(otmShipment.getOtmOrderReleaseList()));
//            itfImplogHeader.setOrderDate();
//            itfImplogHeader.setDeliveryHouseId();
//            itfImplogHeader.setDeliveryHouseCode();
//            itfImplogHeader.setDeliveryHouseName();
//            itfImplogHeader.setRecvHouseId();
//            itfImplogHeader.setRecvHouseCode();
//            itfImplogHeader.setRecvHouseName();
        itfImplogHeader.setCarrierId(otmShipment.getServiceProviderGid());
//            itfImplogHeader.setCarrierName();
        itfImplogHeader.setTransportMethod(otmShipment.getTransportModeGid());
        itfImplogHeader.setPlateNumber(otmShipment.getPlateNo());
//            itfImplogHeader.setDriverName();
//            itfImplogHeader.setDriverPhone();
//            itfImplogHeader.setExpectOutDateLower();
//            itfImplogHeader.setExpectOutDateUpper();
        itfImplogHeader.setExpectInDateLower(otmShipment.getExpectInboundDate());
//            itfImplogHeader.setExpectInDateUpper();
//            itfImplogHeader.setUom();
        itfImplogHeader.setExpectSumQty(new BigDecimal(otmShipment.getTotalShipCount()));
        itfImplogHeader.setLineCount(otmShipment.getOtmOrderReleaseList().size());
        itfImplogHeader.setSourceSystem(SourceSystem.OTM);//OTM触发
        itfImplogHeader.setSourceKey(otmShipment.getShipmentGid());
        itfImplogHeader.setSourceNo(otmShipment.getShipmentGid());
//            itfImplogHeader.setStatus();
        itfImplogHeader.setRemarks(otmShipment.getRemarks());
        itfImplogHeader.setImportTime(new Date());
//            itfImplogHeader.setDataContent();
//            itfImplogHeader.setUserDef0();
//            itfImplogHeader.setUserDef1();
//            itfImplogHeader.setUserDef2();
//            itfImplogHeader.setUserDef3();
//            itfImplogHeader.setUserDef4();
//            itfImplogHeader.setUserDef5();
//            itfImplogHeader.setUserDef6();
//            itfImplogHeader.setUserDef7();
//            itfImplogHeader.setUserDef8();
//            itfImplogHeader.setUserDef9();

        updateById(itfImplogHeader);

        for (OtmOrderRelease otmOrderRelease : otmShipment.getOtmOrderReleaseList()) {
            ItfImplogLine itfImplogLine = new ItfImplogLine();
            itfImplogLine.setId(snowFlakeId.nextId());
            itfImplogLine.setOwnerId(otmOrderRelease.getCustomerId());
            itfImplogLine.setExpectQty(BigDecimal.ONE);
            itfImplogLine.setHeaderId(itfImplogHeader.getId());
            itfImplogLine.setMaterielId(otmOrderRelease.getStanVehicleType());
            itfImplogLine.setLineSourceKey(otmOrderRelease.getReleaseGid());
            itfImplogLine.setLineSourceNo(otmOrderRelease.getReleaseGid());
            itfImplogLine.setLotNo0(otmOrderRelease.getReleaseGid());
            itfImplogLine.setLotNo1(otmOrderRelease.getVin());
            itfImplogHeader.addItfImplogLine(itfImplogLine);
            otmOrderRelease.setLogLineId(itfImplogLine.getId());
//                itfImplogLineService.insert(itfImplogLine);
        }
        List<ItfImplogLine> itfLines = itfImplogHeader.getItfImplogLineList();
        itfImplogLineService.insertBatch(itfLines);
        return itfImplogHeader;
    }

    /**
     * 更新日志导入状态
     */
    private void updateLogImpStatus(Long logHeaderId, String impStatus, String impRemarks) {
        ItfImplogHeader itfImplogHeader = new ItfImplogHeader();
        itfImplogHeader.setImportStatus(impStatus);
        itfImplogHeader.setImportRemarks(impRemarks);
        itfImplogHeader.setId(logHeaderId);
        updateById(itfImplogHeader);
    }

    /**
     * 订单类型
     */
    private String getOrderType(List<OtmOrderRelease> otmOrderReleaseList) {
        EntityWrapper<Storehouse> ewOut = new EntityWrapper<>();
        List<String> outStorehouseCodes = new ArrayList<>();
        List<String> inStorehouseCodes = new ArrayList<>();
        for (OtmOrderRelease otmOrderRelease : otmOrderReleaseList) {
            outStorehouseCodes.add(otmOrderRelease.getOriginLocationGid());
            inStorehouseCodes.add(otmOrderRelease.getDestLocationGid());
        }
        ewOut.in("code", outStorehouseCodes);
        int outCount = storehouseService.selectCount(ewOut);

        EntityWrapper<Storehouse> ewIn = new EntityWrapper<>();
        ewIn.in("code", inStorehouseCodes);
        int inCount = storehouseService.selectCount(ewIn);

        if (outCount > 0 && inCount > 0) {
            return OrderType.MOVEBOUND;
        } else if (outCount > 0) {
            return OrderType.OUTBOUND;
        } else if (inCount > 0) {
            return OrderType.INBOUND;
        } else {
            return OrderType.OTHER;
        }
    }


    private String acquireOrderType(List<Storehouse> outHouses, List<Storehouse> inHouses) {
        if (CollectionUtils.isNotEmpty(outHouses)
                && CollectionUtils.isNotEmpty(inHouses)) {
            return OrderType.MOVEBOUND;
        } else if (CollectionUtils.isNotEmpty(outHouses)) {
            return OrderType.OUTBOUND;
        } else if (CollectionUtils.isNotEmpty(inHouses)) {
            return OrderType.INBOUND;
        } else {
            return OrderType.OTHER;
        }
    }

    private OtmShipment getOtmShipment(ShipmentDTO dto,
                                       ItfImplogHeader header,
                                       HashMap<String, Long> logLineCache,
                                       List<Storehouse> inHouses,
                                       List<Storehouse> outHouses) {
        OtmShipment osm = new OtmShipment();
        osm.setShipmentGid(dto.getShipmentId());
        osm.setShipmentType(dto.getShipmentType());
        osm.setTransactionCode(dto.getTransactionCode());
        osm.setTransportModeGid(dto.getTransportModeId());
        osm.setServiceProviderGid(dto.getServiceProviderId());
        osm.setServiceProviderName(dto.getServiceProviderName());
        osm.setDriverGid(dto.getDriverId());
        osm.setDriverName(dto.getDriverName());
        osm.setDriverPhone(dto.getDriverMoble());
        osm.setPlateNo(dto.getPlateNo());
        osm.setTrailerNo(dto.getTrailerNo());
        osm.setTotalShipCount(dto.getTotalShipCount());
        osm.setExpectInboundDate(dto.getExpectInboundDate());
        osm.setExpectReceiptDate(dto.getExpectReceiptDate());
        osm.setExpcetShipDate(dto.getExpcetShipDate());
        osm.setExpectArriveDate(dto.getExpectArriveDate());
        osm.setLogHeaderId(header.getId());
        osm.setSourceKey(dto.getShipmentId());
        osm.setSourceNo(dto.getShipmentId());
        osm.setOriginLocationGid(dto.getOriginLocationId());
        osm.setOriginLocationName(dto.getOriginLocationName());
        osm.setOriginLocationProvince(dto.getOriginLocationProvince());
        osm.setOriginLocationCity(dto.getOriginLocationCity());
        osm.setOriginLocationCounty(dto.getOriginLocationCounty());
        osm.setOriginLocationAddress(dto.getOriginLocationAddress());
        osm.setDestLocationId(dto.getDestLocationId());
        osm.setDestLocationName(dto.getDestLocationName());
        osm.setDestLocationProvince(dto.getDestLocationProvince());
        osm.setDestLocationCity(dto.getDestLocationCity());
        osm.setDestLocationCounty(dto.getDestLocationCounty());
        osm.setDestLocationAddress(dto.getDestLocationAddress());
        osm.setRemarks(dto.getRemarks());
        osm.setStatus(dto.getStatus());// 取OTM 指令状态
        osm.setGmtCreate(null);
        osm.setGmtModified(null);
        osm.setBoundType(header.getType());
        List<ShipTaskDTO> dtoList = dto.getShipTaskDTOList();
        if (CollectionUtils.isNotEmpty(dtoList)) {
            for (ShipTaskDTO task : dtoList) {
                OtmOrderRelease otr = new OtmOrderRelease();
                otr.setReleaseGid(task.getTaskId());
                otr.setShipmentGid(task.getShipmentId());
                otr.setCustomerId(task.getCustomerId());
                otr.setCusOrderNo(task.getCusWaybillNo()); // 调整存储 客户运单号
                otr.setCusWaybillNo(task.getCusWaybillNo());
                otr.setCusTransMode(task.getCusTransMode());
                otr.setIsUrgent(task.getIsUrgent());
                otr.setPickupIsAppt(task.getPickupIsAppt());
                otr.setOrderAtt(task.getOrderAtt());
                otr.setExpectInboundDate(task.getExpectInboundDate());
                otr.setExpectReceiptDate(task.getExpectReceiptDate());
                otr.setExpcetShipDate(task.getExpcetShipDate());
                otr.setExpectArriveDate(task.getExpectArriveDate());
                otr.setLogLineId(logLineCache.get(task.getTaskId()));
                otr.setSourceKey(task.getTaskId());
                otr.setSourceNo(task.getTaskId());
                otr.setOriginLocationGid(task.getOriginLocationId());
                otr.setOriginLocationName(task.getOriginLocationName());
                otr.setOriginLocationProvince(task.getOriginLocationProvince());
                otr.setOriginLocationCity(task.getOriginLocationCity());
                otr.setOriginLocationCounty(task.getOriginLocationCounty());
                otr.setOriginLocationAddress(task.getOriginLocationAddress());
                otr.setDestLocationGid(task.getDestLocationId());
                otr.setDestLocationName(task.getDestLocationName());
                otr.setDestLocationProvince(task.getDestLocationProvince());
                otr.setDestLocationCity(task.getDestLocationCity());
                otr.setDestLocationCounty(task.getDestLocationCounty());
                otr.setDestLocationAddress(task.getDestLocationAddress());
                otr.setCusVehicleType(task.getCusVehicleType());
                otr.setVehicleDescribe(task.getVehicleDescribe());
                otr.setStanVehicleType(task.getStanVehicleType());
                otr.setVin(task.getVin());
                otr.setIsModVehicle(task.getIsModVehicle());
                otr.setModVehicleSize(task.getModVehicleSize());
                otr.setQrCode(task.getQrCode());
                otr.setRemarks(task.getRemarks());
                otr.setStatus(task.getStatus());  // 取task 运单的状态
                otr.setGmtModified(null);
                otr.setGmtCreate(null);
                for (Storehouse house : outHouses) {
                    if (task.getOriginLocationId().equals(house.getCode())) {
                        otr.setOutboundHouseId(house.getId());
                        break;
                    }
                }
                for (Storehouse house : inHouses) {
                    if (task.getDestLocationId().equals(house.getCode())) {
                        otr.setInboundHouseId(house.getId());
                        break;
                    }
                }
                osm.addOtmOrderRelease(otr);
            }
        }

        return osm;
    }

    private ItfImplogHeader getLogHeader(ShipmentDTO dto,
                                         HashMap<String, Long> logLineCache,
                                         String orderType) {
        List<ShipTaskDTO> taskDTOList = dto.getShipTaskDTOList();
        ItfImplogHeader logHeader = new ItfImplogHeader();
        logHeader.setId(snowFlakeId.nextId());
        if (CollectionUtils.isNotEmpty(taskDTOList)) {
            ShipTaskDTO task = taskDTOList.get(0);
            logHeader.setOwnerId(task.getCustomerId());
            logHeader.setOwnerOrderNo(task.getCusOrderNo());
            logHeader.setDeliveryHouseId(task.getOriginLocationId());
            logHeader.setDeliveryHouseName(task.getOriginLocationName());
            logHeader.setRecvHouseId(task.getDestLocationId());
            logHeader.setRecvHouseName(task.getDestLocationName());
        }
        //logHeader.setRecvHouseCode("");
        //logHeader.setDeliveryHouseCode("");
        logHeader.setType(orderType);
        logHeader.setOrderDate(new Date());
        logHeader.setCarrierId(dto.getServiceProviderId());
        logHeader.setCarrierName(dto.getServiceProviderName());
        logHeader.setTransportMethod(dto.getTransportModeId());
        logHeader.setPlateNumber(dto.getPlateNo());
        logHeader.setDriverName(dto.getDriverName());
        logHeader.setDriverPhone(dto.getDriverMoble());
        logHeader.setExpectOutDateLower(dto.getExpcetShipDate());
        logHeader.setExpectOutDateUpper(dto.getExpcetShipDate());
        logHeader.setExpectInDateLower(dto.getExpectInboundDate());
        logHeader.setExpectInDateUpper(dto.getExpectInboundDate());
        logHeader.setUom(MeasureUnit.TAI);
        logHeader.setExpectSumQty(CollectionUtils.isEmpty(taskDTOList) ? BigDecimal.ZERO : new BigDecimal(taskDTOList.size()));
        logHeader.setLineCount(CollectionUtils.isEmpty(taskDTOList) ? 0 : taskDTOList.size());
        logHeader.setSourceSystem(SourceSystem.OTM);
        logHeader.setSourceKey(dto.getShipmentId());
        logHeader.setSourceNo(dto.getShipmentId());
        logHeader.setStatus(TableStatusEnum.STATUS_10.getCode());
        logHeader.setRemarks("成功");
        logHeader.setImportStatus(TableStatusEnum.STATUS_1.getCode());
        logHeader.setImportRemarks("导入成功");
        logHeader.setImportTime(new Date());
//        logHeader.setDataContent(JSONObject.toJSONString(dto));
        //logHeader.setUserDef0("");
        //logHeader.setUserDef1("");
        //logHeader.setUserDef2("");
        //logHeader.setUserDef3("");
        //logHeader.setUserDef4("");
        //logHeader.setUserDef5("");
        //logHeader.setUserDef6("");
        //logHeader.setUserDef7("");
        logHeader.setUserDef8(SysSourceEnum.NORMAL_TYPE.getName());
        logHeader.setUserDef9(SysSourceEnum.OTM_CREATE.getName());
        logHeader.setGmtCreate(null);
        logHeader.setGmtModified(null);
        if (CollectionUtils.isNotEmpty(taskDTOList)) {
            for (ShipTaskDTO taskDTO : taskDTOList) {
                ItfImplogLine logLine = new ItfImplogLine();
                logLine.setId(snowFlakeId.nextId());
                logLine.setHeaderId(logHeader.getId());
                //logLine.setSeq("");
                logLine.setLineSourceKey(taskDTO.getTaskId());
                logLine.setLineSourceNo(taskDTO.getTaskId());
                logLine.setOwnerId(taskDTO.getCustomerId());
                logLine.setOwnerOrderNo(taskDTO.getCusOrderNo());
                logLine.setMaterielId(taskDTO.getStanVehicleType());
                //logLine.setMaterielCode("");
                //logLine.setMaterielName("");
                logLine.setUom(MeasureUnit.TAI);
                logLine.setExpectQty(BigDecimal.ONE);
                //logLine.setExpectNetWeight(new BigDecimal("0"));
                //logLine.setExpectGrossWeight(new BigDecimal("0"));
                //logLine.setExpectGrossCubage(new BigDecimal("0"));
                //logLine.setExpectPackedCount(new BigDecimal("0"));
                logLine.setRemarks("导入成功");
                //logLine.setLotNo0("");
                logLine.setLotNo1(taskDTO.getVin());
                //logLine.setLotNo2("");
                //logLine.setLotNo3("");
                //logLine.setLotNo4("");
                //logLine.setLotNo5("");
                //logLine.setLotNo6("");
                //logLine.setLotNo7("");
                //logLine.setLotNo8("");
                //logLine.setLotNo9("");
                //logLine.setUserDef0("");
                //logLine.setUserDef1("");
                //logLine.setUserDef2("");
                //logLine.setUserDef3("");
                //logLine.setUserDef4("");
                logLine.setUserDef5(taskDTO.getPickupIsAppt());
                logLine.setUserDef6(taskDTO.getIsModVehicle());//是否改装车
                logLine.setUserDef7(taskDTO.getOrderAtt());
                logLine.setUserDef8(SysSourceEnum.NORMAL_TYPE.getName());
                logLine.setUserDef9(SysSourceEnum.OTM_CREATE.getName());
                logLine.setGmtCreate(null);
                logLine.setGmtModified(null);
                logHeader.addItfImplogLine(logLine);
                logLineCache.put(taskDTO.getTaskId(), logLine.getId());
            }
        }
        return logHeader;
    }

    private void checkParams(ShipmentDTO dto) {
        ShipmentOTMResultDTO resultDTO = new ShipmentOTMResultDTO();
        if (dto == null) {
            resultDTO.setAllCheck("fail");
            resultDTO.setAllRemark("参数为空");
            throw new BaseException("参数为空");
        }
        if (CollectionUtils.isEmpty(dto.getShipTaskDTOList())) {
            resultDTO.setAllCheck("fail");
            resultDTO.setAllRemark("参数为空");
            throw new BaseException("taskList为空");
        }
        if (StringUtils.isBlank(dto.getShipmentId())) {
            resultDTO.setAllCheck("fail");
            resultDTO.setAllRemark("参数为空");
            throw new BaseException("指令号为空");
        }
        if (StringUtils.isBlank(dto.getTransactionCode())) {
            resultDTO.setAllCheck("fail");
            resultDTO.setAllRemark("参数为空");
            throw new BaseException("transactionCode为空");
        }
        List<ShipTaskDTO> taskDTOList = dto.getShipTaskDTOList();
        for (ShipTaskDTO taskDTO : taskDTOList) {

            if (StringUtils.isBlank(taskDTO.getOriginLocationId())) {
                throw new BaseException("起始地ID为空");
            }
            if (StringUtils.isBlank(taskDTO.getDestLocationId())) {
                throw new BaseException("目的地ID为空");
            }
            if (StringUtils.isNotBlank(taskDTO.getVin())) {
                throw new BaseException("车架号为空");
            }
            if (StringUtils.isBlank(taskDTO.getShipmentId())) {
                throw new BaseException("指令号为空");
            }
            if (StringUtils.isBlank(taskDTO.getCustomerId())) {
                throw new BaseException("客户ID为空");
            }
        }
    }
}
